update 20241123

This commit is contained in:
Raki
2024-11-23 19:27:31 +09:00
parent aa8a846898
commit 2bb17daaf1
173 changed files with 50763 additions and 1 deletions

40
.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
db
greybox_tmp
incremental_db
output_files
simulation
hc_output
scaler
hps_isw_handoff
vip
*_sim
.qsys_edit
PLLJ_PLLSPE_INFO.txt
*.bak
*.orig
*.rej
*.qdf
*.rpt
*.smsg
*.summary
*.done
*.jdi
*.pin
*.sof
*.qws
*.ppf
*.ddb
build_id.v
c5_pin_model_dump.txt
*.sopcinfo
*.csv
*.f
*.cmp
*.sip
*.spd
*.bsf
*~
*.xml
*_netlist
*.cdf
**/.DS_Store

31
BubSys.qpf Normal file
View File

@@ -0,0 +1,31 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 2017 Intel Corporation. All rights reserved.
# Your use of Intel 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 Intel Program License
# Subscription Agreement, the Intel Quartus Prime License Agreement,
# the Intel 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 Intel and sold by Intel or its
# authorized distributors. Please refer to the applicable
# agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus Prime
# Version 17.0.0 Build 595 04/25/2017 SJ Lite Edition
# Date created = 10:52:30 August 17, 2024
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "17.0"
DATE = "10:52:30 August 17, 2024"
# Revisions
PROJECT_REVISION = "BubSys"

102
BubSys.qsf Normal file
View File

@@ -0,0 +1,102 @@
# --------------------------------------------------------------------------
#
# MiSTer project
#
# WARNING WARNING WARNING:
# Do not add files to project in Quartus IDE! It will mess this file!
# Add the files manually to files.qip file.
#
# --------------------------------------------------------------------------
set_global_assignment -name TOP_LEVEL_ENTITY sys_top
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
set_global_assignment -name LAST_QUARTUS_VERSION "17.0.0 Lite Edition"
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
set_global_assignment -name SAVE_DISK_SPACE OFF
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
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)"
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS OFF
set_global_assignment -name OPTIMIZE_POWER_DURING_FITTING OFF
set_global_assignment -name FINAL_PLACEMENT_OPTIMIZATION ALWAYS
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON
set_global_assignment -name QII_AUTO_PACKED_REGISTERS NORMAL
set_global_assignment -name ROUTER_LCELL_INSERTION_AND_LOGIC_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
set_global_assignment -name OPTIMIZATION_TECHNIQUE SPEED
set_global_assignment -name MUX_RESTRUCTURE ON
set_global_assignment -name REMOVE_REDUNDANT_LOGIC_CELLS ON
set_global_assignment -name AUTO_DELAY_CHAINS_FOR_HIGH_FANOUT_INPUT_PINS ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON
set_global_assignment -name SYNTH_GATED_CLOCK_CONVERSION ON
set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON
set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON
set_global_assignment -name ECO_OPTIMIZE_TIMING ON
set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name ALM_REGISTER_PACKING_EFFORT MEDIUM
set_global_assignment -name SEED 1
set_global_assignment -name VERILOG_MACRO "MISTER_FB=1"
#enable it only if 8bit indexed mode is used in core
#set_global_assignment -name VERILOG_MACRO "MISTER_FB_PALETTE=1"
#do not enable DEBUG_NOHDMI in release!
#set_global_assignment -name VERILOG_MACRO "MISTER_DEBUG_NOHDMI=1"
# disable bilinear filtering when downscaling
#set_global_assignment -name VERILOG_MACRO "MISTER_DOWNSCALE_NN=1"
# disable adaptive scanline filtering
#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_ADAPTIVE=1"
#use only 1MB per frame for scaler to free ~21MB DDR3 RAM
#set_global_assignment -name VERILOG_MACRO "MISTER_SMALL_VBUF=1"
# Disable YC / Composite output to save some resources
#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_YC=1"
# Disable ALSA audio output to save some resources
#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_ALSA=1"
source sys/sys.tcl
source sys/sys_analog.tcl
source files.qip
set_global_assignment -name ENABLE_SIGNALTAP OFF
set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp
set_global_assignment -name SDC_FILE BubSys.sdc
set_global_assignment -name SYSTEMVERILOG_FILE BubSys.sv
set_global_assignment -name QIP_FILE rtl/pll.qip
set_global_assignment -name VERILOG_FILE rtl/BubSys_emu.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_top.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_cpu.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_sound.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_bbd8/BubSys_bbd8.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_components/BubSys_PROM.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_components/BubSys_SRAM.v
set_global_assignment -name VERILOG_FILE rtl/ipcores/k5289.v
set_global_assignment -name VERILOG_FILE rtl/ipcores/K005297/K005297.v
set_global_assignment -name QIP_FILE rtl/GX400_video/GX400_video.qip
set_global_assignment -name QIP_FILE rtl/ipcores/fx68k/fx68k.qip
set_global_assignment -name QIP_FILE rtl/ipcores/t80/T80.qip
set_global_assignment -name QIP_FILE rtl/ipcores/jtframe_sdram/jtframe_sdram64.qip
set_global_assignment -name QIP_FILE rtl/ipcores/jt49/jt49.qip
set_global_assignment -name QIP_FILE rtl/ipcores/vlm5030_gl/vlm5030_gl.qip
set_global_assignment -name CDF_FILE jtag.cdf
set_global_assignment -name QIP_FILE sys/sys.qip
set_global_assignment -name SIGNALTAP_FILE stp1.stp
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

4
BubSys.sdc Normal file
View File

@@ -0,0 +1,4 @@
derive_pll_clocks
derive_clock_uncertainty
# core specific constraints

29
BubSys.srf Normal file
View File

@@ -0,0 +1,29 @@
{ "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_kbd_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_mouse_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Synthesized away node \"emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|outclk_wire\[2\]\"" { } { } 0 14320 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[1\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[0\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored locations or region assignments to the following nodes" { } { } 0 15705 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[2\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(129): object \"io_win\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(134): object \"io_sdd\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(97): object \"io_win\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(102): object \"io_sdd\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Some pins have incomplete I/O assignments. Refer to the I/O Assignment Warnings report for details" { } { } 0 15714 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "LOCKED port on the PLL is not properly connected on instance \"pll_hdmi:pll_hdmi\|pll_hdmi_0002:pll_hdmi_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Found combinational loop of 47 nodes" { } { } 0 332125 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "LOCKED port on the PLL is not properly connected on instance \"emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at sys_top.v(209): object \"vip_newcfg\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at sys_top.v(594): object \"VSET\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored filter at sys_top.sdc(17): vip\|output_inst\|vid_clk could not be matched with a net" { } { } 0 332174 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored create_generated_clock at sys_top.sdc(16): Argument <targets> is an empty collection" { } { } 0 332049 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored filter at sys_top.sdc(37): VID_CLK could not be matched with a clock" { } { } 0 332174 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "LOCKED port on the PLL is not properly connected on instance \"pll_audio:pll_audio\|pll_audio_0002:pll_audio_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 21074 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 276027 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_pll.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_cyclonev_pll.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_pll_reconfig_core.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "cyclonev_pll" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}

468
BubSys.sv Normal file
View File

@@ -0,0 +1,468 @@
//============================================================================
//
// This program 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 2 of the License, or (at your option)
// any later version.
//
// This program 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, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
module emu
(
//Master input clock
input CLK_50M,
//Async reset from top-level module.
//Can be used as initial reset.
input RESET,
//Must be passed to hps_io module
inout [48:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
//Multiple resolutions are supported using different CE_PIXEL rates.
//Must be based on CLK_VIDEO
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE, // = ~(VBlank | HBlank)
output VGA_F1,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
output VGA_DISABLE, // analog out is off
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
output HDMI_FREEZE,
output HDMI_BLACKOUT,
`ifdef MISTER_FB
// Use framebuffer in DDRAM
// FB_FORMAT:
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
// [3] : 0=16bits 565 1=16bits 1555
// [4] : 0=RGB 1=BGR (for 16/24/32 modes)
//
// FB_STRIDE either 0 (rounded to 256 bytes) or multiple of pixel size (in bytes)
output FB_EN,
output [4:0] FB_FORMAT,
output [11:0] FB_WIDTH,
output [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output FB_FORCE_BLANK,
`ifdef MISTER_FB_PALETTE
// Palette control for 8bit modes.
// Ignored for other video modes.
output FB_PAL_CLK,
output [7:0] FB_PAL_ADDR,
output [23:0] FB_PAL_DOUT,
input [23:0] FB_PAL_DIN,
output FB_PAL_WR,
`endif
`endif
output LED_USER, // 1 - ON, 0 - OFF.
// b[1]: 0 - LED status is system status OR'd with b[0]
// 1 - LED status is controled solely by b[0]
// hint: supply 2'b00 to let the system control the LED.
output [1:0] LED_POWER,
output [1:0] LED_DISK,
// I/O board button press simulation (active high)
// b[1]: user button
// b[0]: osd button
output [1:0] BUTTONS,
input CLK_AUDIO, // 24.576 MHz
output [15:0] AUDIO_L,
output [15:0] AUDIO_R,
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono)
//ADC
inout [3:0] ADC_BUS,
//SD-SPI
output SD_SCK,
output SD_MOSI,
input SD_MISO,
output SD_CS,
input SD_CD,
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
//SDRAM interface with lower latency
output SDRAM_CLK,
output SDRAM_CKE,
output [12:0] SDRAM_A,
output [1:0] SDRAM_BA,
inout [15:0] SDRAM_DQ,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
`ifdef MISTER_DUAL_SDRAM
//Secondary SDRAM
//Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0
input SDRAM2_EN,
output SDRAM2_CLK,
output [12:0] SDRAM2_A,
output [1:0] SDRAM2_BA,
inout [15:0] SDRAM2_DQ,
output SDRAM2_nCS,
output SDRAM2_nCAS,
output SDRAM2_nRAS,
output SDRAM2_nWE,
`endif
input UART_CTS,
output UART_RTS,
input UART_RXD,
output UART_TXD,
output UART_DTR,
input UART_DSR,
// Open-drain User port.
// 0 - D+/RX
// 1 - D-/TX
// 2..6 - USR2..USR6
// Set USER_OUT to 1 to read from USER_IN.
input [6:0] USER_IN,
output [6:0] USER_OUT,
input OSD_STATUS
);
///////// Default values for ports not used in this core /////////
assign ADC_BUS = 'Z;
assign USER_OUT = '1;
assign {UART_RTS, UART_TXD, UART_DTR} = 0;
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = 'Z;
assign LED_DISK = 0;
assign LED_POWER = 0;
assign BUTTONS = 0;
///////////////////////////////////////////////////////////
////// PLL
////
wire CLK72M, CLK57M, CLK48M;
wire pll_locked;
pll pll(
.refclk (CLK_50M ),
.rst (RESET ),
.outclk_0 (CLK72M ),
.outclk_1 (SDRAM_CLK ),
.outclk_2 (CLK57M ),
.outclk_3 (CLK48M ),
.locked (pll_locked )
);
///////////////////////////////////////////////////////////
////// HPS_IO
////
// Status Bit Map:
// Upper Lower
// 0 1 2 3 4 5 6
// 01234567890123456789012345678901 23456789012345678901234567890123
// 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV
// X XXXXXXX X XXXXXXXXXXXXXXXXX
wire [127:0] status; //status bits
`include "build_id.v"
localparam CONF_STR = {
"BubSysROM;",
"-;",
"P1,Scaler Settings;",
"P1-;",
"P1O23,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
"h0P1O4,Orientation,Horizontal,Vertical;",
"P1O5,VGA Scaler,off,on;",
"P1O68,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
"-;",
"P2,Game Settings;",
"P2-;",
"P2OA,Gamma,original,user;",
"P2OS,Swap IRQ,default,IRQ2<=>IRQ1;",
"P2OCF,K5289 volume,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"P2OGJ,VLM volume,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"P2OKN,PSG1 volume,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"P2OOR,PSG2 volume,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"-;",
"DIP;",
"-;",
"R0,Reset and close OSD;",
"J1,Button 1,Button 2,Button 3,Coin,Start,Service;",
"jn,A,B,X,R,Start,Select;",
"V,v",`BUILD_DATE
};
//ioctl
wire [15:0] ioctl_index;
wire ioctl_download;
wire [26:0] ioctl_addr;
wire [7:0] ioctl_data;
wire ioctl_wr;
wire ioctl_wait;
wire [1:0] buttons; //hardware button
wire [15:0] joystick_0;
wire [15:0] joystick_1;
wire forced_scandoubler; //?
wire [21:0] gamma_bus;
wire direct_video;
wire video_rotation; //output from the core
hps_io #(.CONF_STR(CONF_STR)) hps_io
(
.clk_sys (CLK72M ),
.HPS_BUS (HPS_BUS ),
.EXT_BUS ( ),
.buttons (buttons ),
.status (status ),
.status_in (128'h0 ),
.status_menumask ({15'd0, video_rotation} ),
.direct_video (direct_video ),
.new_vmode (1'b0 ),
.forced_scandoubler (forced_scandoubler ),
.gamma_bus (gamma_bus ),
.ioctl_download (ioctl_download ),
.ioctl_upload ( ),
.ioctl_upload_req (1'b0 ),
.ioctl_wr (ioctl_wr ),
.ioctl_addr (ioctl_addr ),
.ioctl_dout (ioctl_data ),
.ioctl_din ( ),
.ioctl_index (ioctl_index ),
.ioctl_wait (ioctl_wait ),
.joystick_0 (joystick_0 ),
.joystick_1 (joystick_1 )
);
///////////////////////////////////////////////////////////
////// CORE
////
wire hsync, vsync;
wire hblank, vblank;
wire [4:0] video_r_5bpp, video_g_5bpp, video_b_5bpp; //need to use color conversion LUT
wire vcen;
reg [3:0] por_delay;
reg soft_reset;
always @(posedge CLK72M) begin
if(RESET | status[0] | buttons[1]) begin
por_delay <= 4'd0;
soft_reset <= 1'b1;
end
else begin
por_delay <= por_delay == 4'd15 ? 4'd15 : por_delay + 4'd1;
soft_reset <= soft_reset != 4'd15;
end
end
assign AUDIO_S = 1'b1;
assign AUDIO_MIX = 2'd0;
BubSys_emu gameboard_top (
.i_EMU_CLK72M (CLK72M ),
.i_EMU_CLK57M (CLK57M ),
.i_EMU_CLK48M (CLK48M ),
.i_EMU_INITRST (RESET ),
.i_EMU_SOFTRST (RESET | status[0] | buttons[1] ),
.o_HBLANK (hblank ),
.o_VBLANK (vblank ),
.o_HSYNC (hsync ),
.o_VSYNC (vsync ),
.o_VIDEO_CEN (vcen ),
.o_VIDEO_DEN ( ),
.o_VIDEO_ROT (video_rotation ),
.o_VIDEO_R (video_r_5bpp ),
.o_VIDEO_G (video_g_5bpp ),
.o_VIDEO_B (video_b_5bpp ),
.i_VOL (status[27:12] ),
.o_SND_L (AUDIO_L ),
.o_SND_R (AUDIO_R ),
.i_MAINCPU_SWAPIRQ (status[28] ),
.o_BMC_ACC (LED_USER ),
.i_JOYSTICK0 (joystick_0 ),
.i_JOYSTICK1 (joystick_1 ),
.ioctl_index (ioctl_index ),
.ioctl_download (ioctl_download ),
.ioctl_addr (ioctl_addr ),
.ioctl_data (ioctl_data ),
.ioctl_wr (ioctl_wr ),
.ioctl_wait (ioctl_wait ),
.sdram_dq (SDRAM_DQ ),
.sdram_a (SDRAM_A ),
.sdram_dqml (SDRAM_DQML ),
.sdram_dqmh (SDRAM_DQMH ),
.sdram_ba (SDRAM_BA ),
.sdram_nwe (SDRAM_nWE ),
.sdram_ncas (SDRAM_nCAS ),
.sdram_nras (SDRAM_nRAS ),
.sdram_ncs (SDRAM_nCS ),
.sdram_cke (SDRAM_CKE ),
.debug ( )
);
//Bubble System resistor network gamma LUT, caculated by MAME's resnet.cpp
function [7:0] bubsys_gamma (input [4:0] bubsys_5bpp); begin
case(bubsys_5bpp)
5'd0 : bubsys_gamma = 8'h00;
5'd1 : bubsys_gamma = 8'h01;
5'd2 : bubsys_gamma = 8'h02;
5'd3 : bubsys_gamma = 8'h04;
5'd4 : bubsys_gamma = 8'h05;
5'd5 : bubsys_gamma = 8'h06;
5'd6 : bubsys_gamma = 8'h08;
5'd7 : bubsys_gamma = 8'h09;
5'd8 : bubsys_gamma = 8'h0B;
5'd9 : bubsys_gamma = 8'h0D;
5'd10: bubsys_gamma = 8'h0F;
5'd11: bubsys_gamma = 8'h12;
5'd12: bubsys_gamma = 8'h14;
5'd13: bubsys_gamma = 8'h16;
5'd14: bubsys_gamma = 8'h19;
5'd15: bubsys_gamma = 8'h1C;
5'd16: bubsys_gamma = 8'h21;
5'd17: bubsys_gamma = 8'h24;
5'd18: bubsys_gamma = 8'h29;
5'd19: bubsys_gamma = 8'h2E;
5'd20: bubsys_gamma = 8'h33;
5'd21: bubsys_gamma = 8'h39;
5'd22: bubsys_gamma = 8'h40;
5'd23: bubsys_gamma = 8'h49;
5'd24: bubsys_gamma = 8'h50;
5'd25: bubsys_gamma = 8'h5B;
5'd26: bubsys_gamma = 8'h68;
5'd27: bubsys_gamma = 8'h78;
5'd28: bubsys_gamma = 8'h8E;
5'd29: bubsys_gamma = 8'hA8;
5'd30: bubsys_gamma = 8'hCC;
5'd31: bubsys_gamma = 8'hFF;
endcase
end endfunction
wire [7:0] video_r_8bpp = status[10] ? {video_r_5bpp, 3'd0} : bubsys_gamma(video_r_5bpp);
wire [7:0] video_g_8bpp = status[10] ? {video_g_5bpp, 3'd0} : bubsys_gamma(video_g_5bpp);
wire [7:0] video_b_8bpp = status[10] ? {video_b_5bpp, 3'd0} : bubsys_gamma(video_b_5bpp);
///////////////////////////////////////////////////////////
////// SCALER
////
assign VGA_F1 = 0;
assign VGA_SCALER = status[5];
assign VGA_DISABLE = 0;
assign HDMI_FREEZE = 0;
assign HDMI_BLACKOUT = 0;
wire [1:0] ar = status[3:2];
wire no_rotate = direct_video | ~status[4];
assign VIDEO_ARX = (!ar) ? no_rotate ? 12'd4 : 12'd3 : (ar - 1'd1);
assign VIDEO_ARY = (!ar) ? no_rotate ? 12'd3 : 12'd4 : 12'd0;
arcade_video #(256,24) arcade_video (
.clk_video (CLK72M ),
.ce_pix (vcen ),
.RGB_in ({video_r_8bpp, video_g_8bpp, video_b_8bpp}),
.HBlank (hblank ),
.VBlank (vblank ),
.HSync (hsync ),
.VSync (vsync ),
.CLK_VIDEO (CLK_VIDEO ),
.CE_PIXEL (CE_PIXEL ),
.VGA_R (VGA_R ),
.VGA_G (VGA_G ),
.VGA_B (VGA_B ),
.VGA_HS (VGA_HS ),
.VGA_VS (VGA_VS ),
.VGA_DE (VGA_DE ),
.VGA_SL (VGA_SL ),
.fx (status[8:6] ), //3bit
.forced_scandoubler (forced_scandoubler ),
.gamma_bus (gamma_bus ) //22bit
);
reg flip = 1'b0;
reg rotate_ccw = 1'b0;
wire video_rotated;
screen_rotate screen_rotate ( .* );
endmodule

339
LICENSE Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 2 of the License, or
(at your option) any later version.
This program 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1 +1,2 @@
# ikacore_Bubsys
Known issue: Vic Viper temporarily disappears at the intruder stage, when you fire laser and missiles simultaneously with quadrupled firepower.
Current status: Fixable, custom chip known as K005295 will be decapped.

36
clean.bat Normal file
View File

@@ -0,0 +1,36 @@
@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
for /d %%i in (sys\*_sim) do rmdir /s /q "%%i"
for /d %%i in (rtl\*_sim) do rmdir /s /q "%%i"
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 *.cdf
del *.rpt
del /s new_rtl_netlist
del /s old_rtl_netlist
pause

22
cr_ie_info.json Normal file
View File

@@ -0,0 +1,22 @@
{
"system" : {
"platform" : "windows64",
"os_name" : "Windows 10",
"os_version" : "10.0"
},
"error" : {
"executable" : "quartus",
"comment" : "not_applicable",
"error_message" : "Access Violation at 0X000001F8ED249940",
"source_file" : "unknown",
"line" : "0",
"stack_trace" : "\t0x1f8ed24993f:\n\t 0x69e5126b: QtGui4 + 0x36126b (?text@QStandardItem@@QEBA?AVQString@@XZ + 0x2b)\n\t0x7ffa051331bb: resr_flowg + 0x31bb (?add_pr_revisions@FLOWG_REVISIONS_LIST@@IEAAXPEAVQStandardItem@@W4ACF_VARIABLE_TYPE_ENUM@@W4ACF_ENUM_VALUE_ENUM@@@Z + 0x9b)\n\t0x7ffa0513709d: resr_flowg + 0x709d (?load_revisions@FLOWG_REVISIONS_LIST@@QEAAXXZ + 0x48d)\n\t 0x6991f9f7: QtCore4 + 0x11f9f7 (?event@QObject@@UEAA_NPEAVQEvent@@@Z + 0xe7)\n\t 0x69b51402: QtGui4 + 0x61402 (?event@QWidget@@MEAA_NPEAVQEvent@@@Z + 0xd42)\n\t 0x69e72676: QtGui4 + 0x382676 (?event@QFrame@@MEAA_NPEAVQEvent@@@Z + 0x36)\n\t 0x69ee3587: QtGui4 + 0x3f3587 (?event@QAbstractScrollArea@@MEAA_NPEAVQEvent@@@Z + 0x257)\n\t 0x69b12e95: QtGui4 + 0x22e95 (?notify_helper@QApplicationPrivate@@QEAA_NPEAVQObject@@PEAVQEvent@@@Z + 0xf5)\n\t 0x69b12b2f: QtGui4 + 0x22b2f (?notify@QApplication@@UEAA_NPEAVQObject@@PEAVQEvent@@@Z + 0x17bf)\n\t 0x6990d92b: QtCore4 + 0x10d92b (?notifyInternal@QCoreApplication@@AEAA_NPEAVQObject@@PEAVQEvent@@@Z + 0x7b)\n\t 0x6990f502: QtCore4 + 0x10f502 (?sendPostedEvents@QCoreApplicationPrivate@@SAXPEAVQObject@@HPEAVQThreadData@@@Z + 0x2b2)\n\t 0x69932fb8: QtCore4 + 0x132fb8 (?processEvents@QEventDispatcherWin32@@UEAA_NV?$QFlags@W4ProcessEventsFlag@QEventLoop@@@@@Z + 0xb98)\n\t0x7ffaab9782e0: USER32 + 0x182e0 (DispatchMessageW + 0x740)\n\t0x7ffaab977da0: USER32 + 0x17da0 (DispatchMessageW + 0x200)\n\t 0x69932802: QtCore4 + 0x132802 (?processEvents@QEventDispatcherWin32@@UEAA_NV?$QFlags@W4ProcessEventsFlag@QEventLoop@@@@@Z + 0x3e2)\n\t 0x69b70eb4: QtGui4 + 0x80eb4 (?openPopup@QApplicationPrivate@@QEAAXPEAVQWidget@@@Z + 0x204)\n\t 0x6990a88b: QtCore4 + 0x10a88b (?exec@QEventLoop@@QEAAHV?$QFlags@W4ProcessEventsFlag@QEventLoop@@@@@Z + 0x22b)\n\t 0x6990ce6f: QtCore4 + 0x10ce6f (?exec@QCoreApplication@@SAHXZ + 0xdf)\n\t0x7ff618f5197b: quartus + 0x197b (?qgq_main@@YAHHPEAPEBD@Z + 0x7b)\n\t0x7ffa84fb2d68: CCL_MSG + 0x12d68 (?msg_main_thread@@YAPEAXPEAX@Z + 0x18)\n\t0x7ffa84fb454e: CCL_MSG + 0x1454e (?msg_thread_wrapper@@YAPEAXP6APEAXPEAX@Z0@Z + 0x6e)\n\t0x7ffa850d5b00: ccl_mem + 0x15b00 (?mem_thread_wrapper@@YAPEAXP6APEAXPEAX@Z0@Z + 0x70)\n\t0x7ffa84fb2631: CCL_MSG + 0x12631 (?msg_exe_main@@YAHHPEAPEBDP6AHH0@Z@Z + 0xa1)\n\t0x7ff618f524e7: quartus + 0x24e7 (WinMain + 0x127)\n\t0x7ff618f51e58: quartus + 0x1e58 (__tmainCRTStartup + 0x148)\n\t0x7ffaab82257c: KERNEL32 + 0x1257c (BaseThreadInitThunk + 0x1c)\n\t0x7ffaac78af27: ntdll + 0x5af27 (RtlUserThreadStart + 0x27)\n",
"subsystem" : "unknown"
},
"quartus" : {
"quartus_bits" : "64",
"version" : "17.0.0",
"build" : "595",
"edition" : "Lite Edition"
}
}

21
files.qip Normal file
View File

@@ -0,0 +1,21 @@
set_global_assignment -name SDC_FILE BubSys.sdc
set_global_assignment -name SYSTEMVERILOG_FILE BubSys.sv
set_global_assignment -name QIP_FILE rtl/pll.qip
set_global_assignment -name VERILOG_FILE rtl/BubSys_emu.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_top.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_cpu.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_sound.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_bbd8/BubSys_bbd8.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_components/BubSys_PROM.v
set_global_assignment -name VERILOG_FILE rtl/BubSys_components/BubSys_SRAM.v
set_global_assignment -name VERILOG_FILE rtl/ipcores/k5289.v
set_global_assignment -name VERILOG_FILE rtl/ipcores/K005297/K005297.v
set_global_assignment -name QIP_FILE rtl/GX400_video/GX400_video.qip
set_global_assignment -name QIP_FILE rtl/ipcores/fx68k/fx68k.qip
set_global_assignment -name QIP_FILE rtl/ipcores/t80/T80.qip
set_global_assignment -name QIP_FILE rtl/ipcores/jtframe_sdram/jtframe_sdram64.qip
set_global_assignment -name QIP_FILE rtl/ipcores/jt49/jt49.qip
set_global_assignment -name QIP_FILE rtl/ipcores/vlm5030_gl/vlm5030_gl.qip

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
module BubSys_PROM #(parameter AW=10, parameter DW=8, parameter simhexfile="") (
input wire i_MCLK,
input wire [AW-1:0] i_PROG_ADDR,
input wire [DW-1:0] i_PROG_DIN,
input wire i_PROG_CS,
input wire i_PROG_WR,
input wire [AW-1:0] i_ADDR,
output reg [DW-1:0] o_DOUT,
input wire i_RD
);
reg [DW-1:0] ROM [0:(2**AW)-1];
always @(posedge i_MCLK) begin
if(i_PROG_CS & i_PROG_WR) ROM[i_PROG_ADDR] <= i_PROG_DIN;
else begin
if(i_RD) o_DOUT <= ROM[i_ADDR];
end
end
initial
begin
if( simhexfile != "" ) begin
$readmemh(simhexfile, ROM);
end
end
endmodule
module BubSys_PROM_DC #(parameter AW=10, parameter DW=8, parameter simhexfile="") (
input wire i_PROG_CLK,
input wire [AW-1:0] i_PROG_ADDR,
input wire [DW-1:0] i_PROG_DIN,
input wire i_PROG_CS,
input wire i_PROG_WR,
input wire i_MCLK,
input wire [AW-1:0] i_ADDR,
output reg [DW-1:0] o_DOUT,
input wire i_RD
);
reg [DW-1:0] ROM [0:(2**AW)-1];
always @(posedge i_PROG_CLK) begin
if(i_PROG_CS && i_PROG_WR) ROM[i_PROG_ADDR] <= i_PROG_DIN;
end
always @(posedge i_MCLK) begin
if(i_RD) o_DOUT <= ROM[i_ADDR];
end
initial
begin
if( simhexfile != "" ) begin
$readmemh(simhexfile, ROM);
end
end
endmodule

View File

@@ -0,0 +1,26 @@
module BubSys_SRAM #(parameter AW=10, parameter DW=8, parameter simhexfile="") (
input wire i_MCLK,
input wire [AW-1:0] i_ADDR,
input wire [DW-1:0] i_DIN,
output reg [DW-1:0] o_DOUT,
input wire i_RD,
input wire i_WR
);
reg [DW-1:0] RAM [0:(2**AW)-1];
always @(posedge i_MCLK) begin
if(i_WR) RAM[i_ADDR] <= i_DIN;
else begin
if(i_RD) o_DOUT <= RAM[i_ADDR];
end
end
integer i;
initial begin
if( simhexfile != "" ) begin
$readmemh(simhexfile, RAM);
end
end
endmodule

746
rtl/BubSys_cpu.v Normal file
View File

@@ -0,0 +1,746 @@
`timescale 10ns/10ns
module BubSys_cpu (
input wire i_EMU_MCLK,
input wire i_EMU_CLK9M_PCEN,
input wire i_EMU_CLK9M_NCEN,
input wire i_EMU_CLK6M_PCEN,
input wire i_EMU_CLK6M_NCEN,
input wire i_EMU_INITRST_n,
input wire i_EMU_SOFTRST_n,
//reset control by the sound CPU
input wire i_MAINCPU_RSTCTRL,
output wire o_MAINCPU_RSTSTAT,
input wire i_MAINCPU_SWAPIRQ,
//bubble memory subsystem
input wire i_BMC_MCLK, //48MHz
input wire i_BMC_TEMPLO_n,
output wire o_BMC_ACC,
output wire [14:0] o_GFX_ADDR,
input wire [15:0] i_GFX_DO,
output wire [15:0] o_GFX_DI,
output wire o_GFX_RnW,
output wire o_GFX_UDS_n,
output wire o_GFX_LDS_n,
output reg o_VZCS_n,
output reg o_VCS1_n,
output reg o_VCS2_n,
output reg o_CHACS_n,
output reg o_OBJRAM_n,
output wire o_HFLIP,
output wire o_VFLIP,
input wire i_ABS_1H_n,
input wire i_ABS_2H,
input wire i_ABS_32H,
input wire i_VBLANK_n,
input wire i_FRAMEPARITY,
input wire i_BLK,
input wire [10:0] i_CD,
//sound interrupts/DMA
output wire o_SND_NMI,
output wire o_SND_INT,
output wire [7:0] o_SND_CODE,
output wire o_SND_DMA_BR,
input wire i_SND_DMA_BG_n,
output wire [14:1] o_SND_DMA_ADDR,
output wire [7:0] o_SND_DMA_DO,
input wire [7:0] i_SND_DMA_DI,
output wire o_SND_DMA_RnW,
output wire o_SND_DMA_LDS_n,
output reg o_SND_DMA_SNDRAM_CS,
input wire i_TIMER_IRQ,
input wire [7:0] i_IN0, i_IN1, i_IN2, i_DIPSW1, i_DIPSW2, i_DIPSW3,
output wire [4:0] o_VIDEO_R,
output wire [4:0] o_VIDEO_G,
output wire [4:0] o_VIDEO_B,
output wire o_BUBROM_BOOT_CS, o_BUBROM_PAGE_CS,
output wire [17:0] o_BUBROM_ADDR,
input wire [15:0] i_BUBROM_DATA,
output wire o_BUBROM_RD,
input wire i_BUBROM_DATA_RDY
);
///////////////////////////////////////////////////////////
////// CLOCK AND RESET
////
//BMC region
wire bmc_rst = ~i_EMU_INITRST_n | ~i_EMU_SOFTRST_n;
wire bmc_maincpu_rstctrl_n;
wire bclk = i_BMC_MCLK;
wire clk4m_pcen;
//Main CPU region
wire maincpu_pwrup = ~i_EMU_INITRST_n;
wire maincpu_rst = ~i_EMU_INITRST_n | ~i_EMU_SOFTRST_n | i_MAINCPU_RSTCTRL | ~bmc_maincpu_rstctrl_n;
wire mclk = i_EMU_MCLK;
wire clk9m_pcen = i_EMU_CLK9M_PCEN;
wire clk9m_ncen = i_EMU_CLK9M_NCEN;
wire clk6m_pcen = i_EMU_CLK6M_PCEN;
wire clk6m_ncen = i_EMU_CLK6M_NCEN;
assign o_MAINCPU_RSTSTAT = maincpu_rst; //watchdog
///////////////////////////////////////////////////////////
////// SYSTEM BUS
////
//dma synchronizer(72MHz/48MHz CDC)
wire dma_br_n, dma_bg_n, dma_bgack_n;
reg [1:0] dma_br_n_sync, dma_bg_n_sync, dma_bgack_n_sync;
wire dma_act = ~dma_bgack_n_sync[1];
always @(posedge mclk) begin //48MHz -> 72MHz
dma_br_n_sync[0] <= dma_br_n;
dma_br_n_sync[1] <= dma_br_n_sync[0];
dma_bgack_n_sync[0] <= dma_bgack_n;
dma_bgack_n_sync[1] <= dma_bgack_n_sync[0];
end
always @(posedge bclk) begin //72MHz -> 48MHz
dma_bg_n_sync[0] <= dma_bg_n;
dma_bg_n_sync[1] <= dma_bg_n_sync[0];
end
//Main 68k bus/control
wire [15:0] maincpu_do;
wire [23:1] maincpu_addr;
wire maincpu_as_n, maincpu_r_nw, maincpu_lds_n, maincpu_uds_n;
wire [2:0] maincpu_fc;
//Bubble memory controller bus/control
wire [15:0] bmc_di, bmc_do;
wire bmc_ale; //address latch enable(48MHz)
reg [15:0] bmc_al; //address latch LS272*2
reg [2:0] bmc_ale_sync;
always @(posedge mclk) begin
bmc_ale_sync[0] <= bmc_ale;
bmc_ale_sync[2:1] <= bmc_ale_sync[1:0];
if(bmc_ale_sync[2:1] == 2'b01) bmc_al <= bmc_do;
end
wire [7:1] bmc_addr;
wire bmc_as_n, bmc_r_nw, bmc_lds_n, bmc_uds_n;
reg [1:0] bmc_as_n_sync, bmc_r_nw_sync;
reg [3:0] bmc_lds_n_sync, bmc_uds_n_sync;
reg bmc_lds_n_negedge, bmc_uds_n_negedge;
always @(posedge mclk) begin
bmc_as_n_sync[0] <= bmc_as_n;
bmc_r_nw_sync[0] <= bmc_r_nw;
bmc_as_n_sync[1] <= bmc_as_n_sync[0];
bmc_r_nw_sync[1] <= bmc_r_nw_sync[0];
bmc_lds_n_sync[0] <= bmc_lds_n;
bmc_uds_n_sync[0] <= bmc_uds_n;
bmc_lds_n_sync[3:1] <= bmc_lds_n_sync[2:0];
bmc_uds_n_sync[3:1] <= bmc_uds_n_sync[2:0];
bmc_lds_n_negedge <= bmc_lds_n_sync[3] && !bmc_lds_n_sync[1];
bmc_uds_n_negedge <= bmc_uds_n_sync[3] && !bmc_uds_n_sync[1];
end
wire [2:0] bmc_fc;
//Main bus/control, CPU+BMC multiplexed
reg [15:0] mainbus_di;
wire [15:0] mainbus_do = dma_act ? bmc_do : maincpu_do; //no need to synchronize
wire [23:1] mainbus_addr = dma_act ? {bmc_al, bmc_addr} : maincpu_addr; //no need to synchronize
wire mainbus_as_n = dma_act ? bmc_as_n_sync[1] : maincpu_as_n;
wire mainbus_r_nw = dma_act ? bmc_r_nw_sync[1] : maincpu_r_nw;
wire mainbus_lds_n = dma_act ? ~bmc_lds_n_negedge : maincpu_lds_n;
wire mainbus_uds_n = dma_act ? ~bmc_uds_n_negedge : maincpu_uds_n;
wire [2:0] mainbus_fc = dma_act ? bmc_fc : maincpu_fc;
assign bmc_di = dma_act ? mainbus_di : mainbus_do;
wire [23:0] debug_mainbus_addr = {mainbus_addr, mainbus_uds_n};
//send signals to the GFX board
assign o_GFX_ADDR = mainbus_addr[15:1];
assign o_GFX_DI = mainbus_do;
assign o_GFX_RnW = mainbus_r_nw;
assign o_GFX_UDS_n = mainbus_uds_n;
assign o_GFX_LDS_n = mainbus_lds_n;
///////////////////////////////////////////////////////////
////// MAIN CPU
////
reg maincpu_vpa_n;
reg maincpu_dtack_n;
reg [2:0] maincpu_ipl;
fx68k u_maincpu (
.clk (mclk ),
.HALTn (1'b1 ),
.extReset (maincpu_rst ),
.pwrUp (maincpu_pwrup ),
.enPhi1 (clk9m_pcen ),
.enPhi2 (clk9m_ncen ),
.eRWn (maincpu_r_nw ),
.ASn (maincpu_as_n ),
.LDSn (maincpu_lds_n ),
.UDSn (maincpu_uds_n ),
.E ( ),
.VMAn ( ),
.iEdb (mainbus_di ), //data bus in
.oEdb (maincpu_do ), //data bus out
.eab (maincpu_addr ), //23 downto 1
.FC0 (maincpu_fc[0] ),
.FC1 (maincpu_fc[1] ),
.FC2 (maincpu_fc[2] ),
.BGn (dma_bg_n ),
.oRESETn ( ),
.oHALTEDn ( ),
.DTACKn (maincpu_dtack_n ),
.VPAn (maincpu_vpa_n ),
.BERRn (1'b1 ),
.BRn (dma_br_n_sync[1] ),
.BGACKn (dma_bgack_n_sync[1] ),
.IPL0n (maincpu_ipl[0] ),
.IPL1n (maincpu_ipl[1] ),
.IPL2n (maincpu_ipl[2] )
);
///////////////////////////////////////////////////////////
////// BUBBLE MEMORY
////
reg bmc_cs;
wire bmcclk_pcen; //generated by bubble memory emulator
wire booten_n, bss_n, bsen_n, repen_n, swapen_n;
wire [3:0] bdo_n;
BubSys_bbd8 u_bbd8 (
.i_EMUCLK (bclk ),
.i_RST (bmc_rst ),
.i_4BEN (1'b0 ),
.i_BDO_TSEL (1'b0 ),
.o_BMCCLK_PCEN (bmcclk_pcen ),
.i_BOOTEN_n (booten_n ),
.i_BSS_n (bss_n ),
.i_BSEN_n (bsen_n ),
.i_REPEN_n (repen_n ),
.i_SWAPEN_n (swapen_n ),
.o_BDO_n (bdo_n ),
.o_ACC (o_BMC_ACC ),
.o_BUBROM_BOOT_CS (o_BUBROM_BOOT_CS ),
.o_BUBROM_PAGE_CS (o_BUBROM_PAGE_CS ),
.o_BUBROM_ADDR (o_BUBROM_ADDR ),
.i_BUBROM_DATA (i_BUBROM_DATA ),
.o_BUBROM_RD (o_BUBROM_RD ),
.i_BUBROM_DATA_RDY (i_BUBROM_DATA_RDY )
);
///////////////////////////////////////////////////////////
////// BUBBLE MEMORY CONTROLLER
////
wire bmc_irq_n;
K005297 u_K005297 (
.i_MCLK (bclk ),
.i_CLK4M_PCEN_n (~bmcclk_pcen ),
.i_MRST_n (~bmc_rst ),
.i_REGCS_n (~bmc_cs ),
.i_DIN (bmc_di ), //write to BMC/BMC DMA read
.i_AIN (mainbus_addr[3:1] ), //write to BMC
.i_R_nW (mainbus_r_nw ),
.i_UDS_n (mainbus_uds_n ),
.i_LDS_n (mainbus_lds_n ),
.i_AS_n (mainbus_as_n ),
.o_DOUT (bmc_do ),
.o_AOUT (bmc_addr ),
.o_R_nW (bmc_r_nw ),
.o_UDS_n (bmc_uds_n ),
.o_LDS_n (bmc_lds_n ),
.o_AS_n (bmc_as_n ),
.o_ALE (bmc_ale ),
.o_BR_n (dma_br_n ),
.i_BG_n (dma_bg_n_sync[1] ),
.o_BGACK_n (dma_bgack_n ),
.o_CPURST_n (bmc_maincpu_rstctrl_n ),
.o_IRQ_n (bmc_irq_n ),
.o_FCOUT (bmc_fc ),
.i_FCIN (mainbus_fc ),
.o_BDOUT_n ( ),
.i_BDIN_n ({bdo_n[1:0], 2'b11} ),
.o_BOOTEN_n (booten_n ),
.o_BSS_n (bss_n ),
.o_BSEN_n (bsen_n ),
.o_REPEN_n (repen_n ),
.o_SWAPEN_n (swapen_n ),
.i_TEMPLO_n (1'b1 ),
.o_HEATEN_n ( ),
.i_4BEN_n (1'b1 ),
.o_INT1_ACK_n ( ),
.i_TST1 (1'b1 ),
.i_TST2 (1'b0 ),
.i_TST3 (1'b1 ),
.i_TST4 (1'b0 ),
.i_TST5 (1'b1 ),
.o_CTRL_DMAIO_OE_n ( ),
.o_CTRL_DATA_OE_n ( )
);
///////////////////////////////////////////////////////////
////// ADDRESS DECODER
////
reg sharedram_cs, gamerom_rd, workram_cs, extram_cs;
reg dmastat_cs, sndlatch_cs;
reg palram_cs;
reg syscfg_cs, dip_cs, btn_cs;
always @(*) begin
sharedram_cs= 1'b0; //shared RAM between BMC/CPU
gamerom_rd = 1'b0;
workram_cs = 1'b0;
bmc_cs = 1'b0;
extram_cs = 1'b0;
dmastat_cs = 1'b0;
sndlatch_cs = 1'b0;
o_SND_DMA_SNDRAM_CS = 1'b0;
syscfg_cs = 1'b0;
dip_cs = 1'b0;
btn_cs = 1'b0;
palram_cs = 1'b0;
o_VZCS_n = 1'b1;
o_VCS1_n = 1'b1;
o_VCS2_n = 1'b1;
o_CHACS_n = 1'b1;
o_OBJRAM_n = 1'b1;
maincpu_vpa_n = 1'b1;
if(!mainbus_as_n && mainbus_addr[23:19] == 5'b00000) begin
//1st LS138
sharedram_cs= mainbus_addr[18:16] == 3'b000; //0x000000-0x000FFF, 6116*2
workram_cs = mainbus_addr[18:16] == 3'b001; //0x010000-0x01FFFF, 62256*2
o_SND_DMA_SNDRAM_CS = mainbus_addr[18:16] == 3'b010; //0x020000-0x027FFF, sound RAM address space
o_CHACS_n = ~(mainbus_addr[18:16] == 3'b011); //0x030000-0x03FFFF, 4416*8
bmc_cs = mainbus_addr[18:16] == 3'b100; //0x040000-0x04FFFF, bubble memory controller
extram_cs = mainbus_addr[18:16] == 3'b111; //0x070000-0x07FFFF, 6264*2(expansion RAM)
//2nd LS138
if(mainbus_addr[18:16] == 3'b101) begin
o_VZCS_n = ~(mainbus_addr[15:13] == 3'b000); //0x190000-0x190FFF, 16k*1, byte only
o_VCS1_n = ~(mainbus_addr[15:13] == 3'b001); //0x100000-0x101FFF, 32k*2, Toshiba 32kbit TC5533
o_VCS2_n = ~(mainbus_addr[15:13] == 3'b010); //0x102000-0x103FFF, 32k*1, byte only
o_OBJRAM_n = ~(mainbus_addr[15:13] == 3'b011); //0x180000-0x180FFF, 16k*1, byte only
palram_cs = mainbus_addr[15:13] == 3'b101; //0x090000-0x091FFF, 16k*2, byte only
syscfg_cs = mainbus_addr[15:13] == 3'b111;
end
//3rd LS138
if(mainbus_addr[18:13] == 6'b101_110 && !mainbus_lds_n) begin
sndlatch_cs = mainbus_addr[12:10] == 3'b000;
dip_cs = mainbus_addr[12:10] == 3'b001;
btn_cs = mainbus_addr[12:10] == 3'b011;
dmastat_cs = mainbus_addr[12:10] == 3'b100;
end
end
maincpu_vpa_n = mainbus_as_n | ~mainbus_addr[23];
end
///////////////////////////////////////////////////////////
////// MAIN CPU DTACK
////
//work ram timings
reg abs_32h_z;
wire abs_32h_pe = i_ABS_32H & ~abs_32h_z;
always @(posedge mclk) if(clk6m_pcen) abs_32h_z <= i_ABS_32H;
reg [2:0] workram_rfsh_stat = 3'd0; //0 = idle, 1, 2, 3 = refresh, 4 = refresh pending
always @(posedge mclk) if(clk6m_pcen) begin
if(workram_rfsh_stat == 3'd0) begin
if(workram_cs) begin
if(abs_32h_pe) workram_rfsh_stat <= 3'd4;
end
else begin
if(abs_32h_pe) workram_rfsh_stat <= workram_rfsh_stat + 2'd1;
end
end
else if(workram_rfsh_stat == 3'd4) begin
if(!workram_cs) workram_rfsh_stat <= 3'd1;
end
else begin
if(workram_rfsh_stat == 3'd3) workram_rfsh_stat <= 3'd0;
else workram_rfsh_stat <= workram_rfsh_stat + 3'd1;
end
end
//dtack generator
wire dtack0_n = 1'b0;
reg dtack1_n, dtack2_pre_n, dtack2_n;
wire dtack3_n = ~((workram_rfsh_stat == 3'd0 | workram_rfsh_stat == 3'd4) & workram_cs);
always @(posedge mclk) begin
if(maincpu_uds_n & maincpu_lds_n) begin
dtack1_n <= 1'b1;
dtack2_pre_n <= 1'b1;
dtack2_n <= 1'b1;
end
else begin
if(clk6m_pcen) begin
if(!i_ABS_1H_n) dtack1_n <= 1'b0;
dtack2_pre_n <= 1'b0;
end
if(clk6m_ncen) begin
if({i_ABS_2H, ~i_ABS_1H_n} == 2'b00) dtack2_n <= dtack2_pre_n;
end
end
end
//DTACK selector
wire [1:0] dtack_sel;
assign dtack_sel[1] = workram_cs | bmc_cs | o_SND_DMA_SNDRAM_CS | ~o_CHACS_n | ~o_VCS1_n | ~o_VCS2_n; // | exdtack <- not used, never used
assign dtack_sel[0] = workram_cs | ~o_VZCS_n | ~o_OBJRAM_n;
always @(*) begin
case(dtack_sel)
2'd0: maincpu_dtack_n = dtack0_n; //bootloader ROM, program ROM(2Mbit), IO spaces
2'd1: maincpu_dtack_n = dtack1_n; //scrollram, objram
2'd2: maincpu_dtack_n = dtack2_n; //soundram, charram, vram1, vram2
2'd3: maincpu_dtack_n = dtack3_n; //workram
endcase
end
///////////////////////////////////////////////////////////
////// MAIN CPU IRQ
////
wire iack_vblank_n, iack_fparity_n, iack_timer_n;
reg vblank_z, vblank_zz, fparity_z, fparity_zz, timer_z, timer_zz, bmc_irq_n_z, bmc_irq_n_zz;
reg irq_vblank_n, irq_fparity_n, irq_timer_n;
always @(posedge mclk) begin
vblank_z <= ~i_VBLANK_n;
vblank_zz <= vblank_z;
fparity_z <= i_FRAMEPARITY;
fparity_zz <= fparity_z;
timer_z <= i_TIMER_IRQ;
timer_zz <= timer_z;
bmc_irq_n_z <= bmc_irq_n;
bmc_irq_n_zz <= bmc_irq_n_z;
if(maincpu_rst) begin
irq_vblank_n <= 1'b1;
irq_fparity_n <= 1'b1;
irq_timer_n <= 1'b1;
end
else begin
if(!iack_vblank_n) irq_vblank_n <= 1'b1;
else begin
if({vblank_zz, vblank_z} == 2'b01) irq_vblank_n <= 1'b0;
end
if(!iack_fparity_n) irq_fparity_n <= 1'b1;
else begin
if({fparity_zz, fparity_z} == 2'b01) irq_fparity_n <= 1'b0;
end
if(!iack_timer_n) irq_timer_n <= 1'b1;
else begin
if({timer_zz, timer_z} == 2'b01) irq_timer_n <= 1'b0;
end
end
end
//Bubble System uses LS147 only, not make a delayed signal
always @(*) begin
if(!bmc_irq_n_zz) maincpu_ipl = 3'b010;
else begin
if(!irq_timer_n) maincpu_ipl = 3'b011;
else begin
if(i_MAINCPU_SWAPIRQ ? !irq_fparity_n : !irq_vblank_n) maincpu_ipl = 3'b101;
else begin
if(i_MAINCPU_SWAPIRQ ? !irq_vblank_n : !irq_fparity_n) maincpu_ipl = 3'b110;
else maincpu_ipl = 3'b111;
end
end
end
end
///////////////////////////////////////////////////////////
////// OUTLATCH(SYSTEM CONFIGURATION)
////
reg [5:0] syscfg[0:1];
always @(posedge mclk) begin
if(maincpu_rst) begin
syscfg[0] <= 6'h00;
syscfg[1] <= 6'h00;
end
else begin if(syscfg_cs) begin
if(!mainbus_uds_n && !mainbus_r_nw) begin
case(mainbus_addr[3:1])
//3'd0: syscfg[0][0] <= maincpu_do[8]; //coin counter 1
//3'd1: syscfg[0][1] <= maincpu_do[8];
3'd2: syscfg[0][2] <= mainbus_do[8]; //sound interrupt tick
3'd3: syscfg[0][3] <= mainbus_do[8]; //dma_busrq
3'd4: syscfg[0][4] <= mainbus_do[8]; //sound NMI
3'd7: syscfg[0][5] <= mainbus_do[8]; //timerirq_ack_n
default: ;
endcase
end
if(!mainbus_lds_n && !mainbus_r_nw) begin
case(mainbus_addr[3:1])
3'd0: syscfg[1][0] <= mainbus_do[0]; //vblankirq_ack_n
3'd1: syscfg[1][1] <= mainbus_do[0]; //frameirq_ack_n
3'd2: syscfg[1][2] <= mainbus_do[0]; //gfx_hflip
3'd3: syscfg[1][3] <= mainbus_do[0]; //gfx_vflip
//3'd4: syscfg[1][4] <= maincpu_do[0]; //gfx_h288
//3'd5: syscfg[1][5] <= maincpu_do[0]; //gfx_interlaced
default: ;
endcase
end
end end
end
assign iack_vblank_n = syscfg[1][0];
assign iack_fparity_n = syscfg[1][1];
assign iack_timer_n = syscfg[0][5];
assign o_HFLIP = syscfg[1][2];
assign o_VFLIP = syscfg[1][3];
assign o_SND_INT = syscfg[0][2];
assign o_SND_NMI = syscfg[0][4];
///////////////////////////////////////////////////////////
////// WORK RAM
////
wire [15:0] sharedram_q;
BubSys_SRAM #(.AW(11), .DW(8), .simhexfile()) u_sharedram_hi (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[11:1] ),
.i_DIN (mainbus_do[15:8] ),
.o_DOUT (sharedram_q[15:8] ),
.i_WR (sharedram_cs & ~mainbus_r_nw & ~mainbus_uds_n & mainbus_fc[2]),
.i_RD (sharedram_cs & mainbus_r_nw & ~mainbus_uds_n & mainbus_fc[2])
);
BubSys_SRAM #(.AW(11), .DW(8), .simhexfile()) u_sharedram_lo (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[11:1] ),
.i_DIN (mainbus_do[7:0] ),
.o_DOUT (sharedram_q[7:0] ),
.i_WR (sharedram_cs & ~mainbus_r_nw & ~mainbus_lds_n & mainbus_fc[2]),
.i_RD (sharedram_cs & mainbus_r_nw & ~mainbus_lds_n & mainbus_fc[2])
);
wire [15:0] workram_q;
BubSys_SRAM #(.AW(15), .DW(8), .simhexfile()) u_workram_hi (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[15:1] ),
.i_DIN (mainbus_do[15:8] ),
.o_DOUT (workram_q[15:8] ),
.i_WR (workram_cs & ~mainbus_r_nw & ~mainbus_uds_n),
.i_RD (workram_cs & mainbus_r_nw & ~mainbus_uds_n)
);
BubSys_SRAM #(.AW(15), .DW(8), .simhexfile()) u_workram_lo (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[15:1] ),
.i_DIN (mainbus_do[7:0] ),
.o_DOUT (workram_q[7:0] ),
.i_WR (workram_cs & ~mainbus_r_nw & ~mainbus_lds_n),
.i_RD (workram_cs & mainbus_r_nw & ~mainbus_lds_n)
);
//6264*2, gradius uses this
wire [15:0] extram_q;
BubSys_SRAM #(.AW(13), .DW(8), .simhexfile()) u_extram_hi (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[13:1] ),
.i_DIN (mainbus_do[15:8] ),
.o_DOUT (extram_q[15:8] ),
.i_WR (extram_cs & ~mainbus_r_nw & ~mainbus_uds_n),
.i_RD (extram_cs & mainbus_r_nw & ~mainbus_uds_n)
);
BubSys_SRAM #(.AW(13), .DW(8), .simhexfile()) u_extram_lo (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (mainbus_addr[13:1] ),
.i_DIN (mainbus_do[7:0] ),
.o_DOUT (extram_q[7:0] ),
.i_WR (extram_cs & ~mainbus_r_nw & ~mainbus_lds_n),
.i_RD (extram_cs & mainbus_r_nw & ~mainbus_lds_n)
);
///////////////////////////////////////////////////////////
////// Palette RAM
////
//make palram wr signal
wire palram_hi_cs = &{palram_cs, ~mainbus_uds_n};
wire palram_lo_cs = &{palram_cs, ~mainbus_lds_n};
//make colorram address
wire [10:0] palram_addr = palram_cs ? mainbus_addr[11:1] : i_CD;
//declare COLORRAM
wire [7:0] palram_lo_q, palram_hi_q;
wire [15:0] palram_q = {palram_hi_q, palram_lo_q};
BubSys_SRAM #(.AW(11), .DW(8), .simhexfile()) u_palram_hi (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (palram_addr ),
.i_DIN (mainbus_do[15:8] ),
.o_DOUT (palram_hi_q ),
.i_WR (palram_hi_cs & ~mainbus_r_nw),
.i_RD (1'b1 )
);
BubSys_SRAM #(.AW(11), .DW(8), .simhexfile()) u_palram_lo (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (palram_addr ),
.i_DIN (mainbus_do[7:0] ),
.o_DOUT (palram_lo_q ),
.i_WR (palram_lo_cs & ~mainbus_r_nw),
.i_RD (1'b1 )
);
//rgb driver latch
reg [14:0] rgblatch;
always @(posedge mclk) if(clk6m_pcen) begin
rgblatch <= {palram_hi_q[6:0], palram_lo_q};
end
assign o_VIDEO_B = i_BLK ? rgblatch[14:10] : 5'd0;
assign o_VIDEO_G = i_BLK ? rgblatch[9:5] : 5'd0;
assign o_VIDEO_R = i_BLK ? rgblatch[4:0] : 5'd0;
///////////////////////////////////////////////////////////
////// SOUNDLATCH
////
reg [7:0] soundlatch = 8'h00;
assign o_SND_CODE = soundlatch;
always @(posedge mclk) begin
if(sndlatch_cs && !mainbus_r_nw && !mainbus_lds_n) soundlatch <= mainbus_do[7:0];
end
///////////////////////////////////////////////////////////
////// DMA
////
assign o_SND_DMA_BR = syscfg[0][3]; //sound cpu bus request
assign o_SND_DMA_ADDR = mainbus_addr[14:1];
assign o_SND_DMA_DO = mainbus_do[7:0];
assign o_SND_DMA_RnW = mainbus_r_nw;
assign o_SND_DMA_LDS_n = mainbus_lds_n;
///////////////////////////////////////////////////////////
////// READ BUS MUX
////
//assign o_BMC_ACC = mainbus_fc == 3'b110 && mainbus_addr == 23'h8000 /* synthesis keep */;
wire gfx_cs = ~&{o_VZCS_n, o_VCS1_n, o_VCS2_n, o_CHACS_n, o_OBJRAM_n};
//CDC synchronizer
reg [7:0] snd_dma_di_sync[0:1];
reg [1:0] snd_dma_bg_n_sync;
always @(posedge mclk) begin
snd_dma_di_sync[0] <= i_SND_DMA_DI;
snd_dma_di_sync[1] <= snd_dma_di_sync[0];
snd_dma_bg_n_sync[0] <= i_SND_DMA_BG_n;
snd_dma_bg_n_sync[1] <= snd_dma_bg_n_sync[0];
end
always @(*) begin
mainbus_di = 16'hFFFF;
if(bmc_cs) mainbus_di = bmc_do;
else if(sharedram_cs) mainbus_di = sharedram_q;
else if(workram_cs) mainbus_di = workram_q;
else if(extram_cs) mainbus_di = extram_q;
else if(palram_cs) mainbus_di = palram_q;
else if(gfx_cs) mainbus_di = i_GFX_DO;
else if(btn_cs) begin
case(mainbus_addr[2:1])
2'd0: mainbus_di = {8'hFF, i_IN0};
2'd1: mainbus_di = {8'hFF, i_IN1};
2'd2: mainbus_di = {8'hFF, i_IN2};
2'd3: mainbus_di = {16'hFFFF};
endcase
end
else if(dip_cs) begin
case(mainbus_addr[2:1])
2'd0: mainbus_di = {16'hFFFF};
2'd1: mainbus_di = {8'hFF, i_DIPSW1};
2'd2: mainbus_di = {8'hFF, i_DIPSW2};
2'd3: mainbus_di = {8'hFF, i_DIPSW3};
endcase
end
else if(o_SND_DMA_SNDRAM_CS) mainbus_di = {8'hFF, snd_dma_di_sync[1]};
else if(dmastat_cs) mainbus_di = {{15{1'b1}}, snd_dma_bg_n_sync[1]};
end
endmodule

476
rtl/BubSys_emu.v Normal file
View File

@@ -0,0 +1,476 @@
module BubSys_emu (
input wire i_EMU_CLK72M,
input wire i_EMU_CLK57M,
input wire i_EMU_CLK48M,
input wire i_EMU_INITRST,
input wire i_EMU_SOFTRST,
//video syncs
output wire o_HBLANK,
output wire o_VBLANK,
output wire o_HSYNC,
output wire o_VSYNC,
output wire o_VIDEO_CEN, //video clock enable
output wire o_VIDEO_DEN, //video data enable
output wire o_VIDEO_ROT, //only for twinbee
output wire [4:0] o_VIDEO_R,
output wire [4:0] o_VIDEO_G,
output wire [4:0] o_VIDEO_B,
input wire [15:0] i_VOL,
output wire signed [15:0] o_SND_L,
output wire signed [15:0] o_SND_R,
input wire i_MAINCPU_SWAPIRQ,
output wire o_BMC_ACC,
input wire [15:0] i_JOYSTICK0,
input wire [15:0] i_JOYSTICK1,
//mister ioctl
input wire [15:0] ioctl_index,
input wire ioctl_download,
input wire [26:0] ioctl_addr,
input wire [7:0] ioctl_data,
input wire ioctl_wr,
output wire ioctl_wait,
//mister sdram
inout wire [15:0] sdram_dq,
output wire [12:0] sdram_a,
output wire sdram_dqml,
output wire sdram_dqmh,
output wire [1:0] sdram_ba,
output wire sdram_nwe,
output wire sdram_ncas,
output wire sdram_nras,
output wire sdram_ncs,
output wire sdram_cke,
output wire debug
);
///////////////////////////////////////////////////////////
////// ROM DISTRIBUTOR
////
//start addr length comp num mame rom parts num location description
//0x0000_0000 0x0004_0FFF FBM54DB BANK0 bubble memory user page
//0x0004_1000 0x0000_2000 5l 400-a~e03 27C64 BRAM sound program(bootloader/base)
//0x0004_3000 0x0000_0200 FBM54DB BRAM bubble memory bootloader
//0x0004_3200 0x0000_0100 2a 400-a01 82S129 BRAM wavetable
//0x0004_3300 0x0000_0100 1a 400-a02 82S129 BRAM wavetable
//0x0004_3400 <-----------------ROM END----------------->
//dipsw bank
reg [7:0] DIPSW1 = 8'hFF;
reg [7:0] DIPSW2 = 8'h42;
reg [7:0] DIPSW3 = 8'hFF;
reg [7:0] CORECONFIG = 8'h00;
assign o_VIDEO_ROT = CORECONFIG[1:0] == 2'd0;
///////////////////////////////////////////////////////////
////// SDRAM/BRAM DOWNLOADER INTERFACE
////
//download complete
reg rom_download_done = 1'b0;
//enables
reg prog_sdram_en = 1'b0;
reg prog_bram_en = 1'b0;
//sdram control
wire sdram_init;
reg prog_sdram_wr_busy = 1'b0;
wire prog_sdram_ack;
assign ioctl_wait = sdram_init | prog_sdram_wr_busy;
//assign ioctl_wait = 1'b0;
reg [1:0] prog_sdram_bank_sel;
reg [21:0] prog_sdram_addr;
reg [1:0] prog_sdram_mask;
reg [15:0] prog_sdram_din_buf;
//bram control
reg [13:0] prog_bram_addr;
reg [7:0] prog_bram_din_buf;
reg prog_bram_wr;
reg [3:0] prog_bram_csreg;
wire prog_bram_wave2_cs = prog_bram_csreg[3];
wire prog_bram_wave1_cs = prog_bram_csreg[2];
wire prog_bram_bootrom_cs = prog_bram_csreg[1];
wire prog_bram_sndrom_cs = prog_bram_csreg[0];
assign debug = rom_download_done;
//state machine
always @(posedge i_EMU_CLK72M) begin
if((i_EMU_INITRST | rom_download_done) == 1'b1) begin
if(i_EMU_INITRST) rom_download_done <= 1'b0;
//enables
prog_sdram_en <= 1'b0;
prog_bram_en <= 1'b0;
//sdram
prog_sdram_addr <= 22'h3F_FFFF;
prog_sdram_wr_busy <= 1'b0;
prog_sdram_bank_sel <= 2'd0;
prog_sdram_mask <= 2'b00;
prog_sdram_din_buf <= 16'hFFFF;
//bram
prog_bram_din_buf <= 8'hFF;
prog_bram_addr <= 14'h3FFF;
prog_bram_wr <= 1'b0;
prog_bram_csreg <= 4'b0000;
if(ioctl_index == 16'd254) begin //DIP SWITCH
if(ioctl_wr == 1'b1) begin
if(ioctl_addr[2:0] == 3'd0) DIPSW1 <= ioctl_data;
else if(ioctl_addr[2:0] == 3'd1) DIPSW2 <= ioctl_data;
else if(ioctl_addr[2:0] == 3'd2) DIPSW3 <= ioctl_data;
else if(ioctl_addr[2:0] == 3'd3) CORECONFIG <= ioctl_data;
end
end
end
else begin
// ROM DATA UPLOAD
if(ioctl_index == 16'd0) begin //ROM DATA
// BLOCK RAM REGION
if(ioctl_addr[19:12] > 8'h4_0 ) begin
prog_sdram_en <= 1'b0;
prog_bram_en <= 1'b1;
if(ioctl_wr == 1'b1) begin
prog_bram_din_buf <= ioctl_data;
prog_bram_addr <= ioctl_addr[13:0] - 14'h1000;
prog_bram_wr <= 1'b1;
if(ioctl_addr[13:12] == 2'd1 || ioctl_addr[13:12] == 2'd2) prog_bram_csreg <= 4'b0001; //sound rom
else begin
if(ioctl_addr[9:8] == 2'd0 || ioctl_addr[9:8] == 2'd1) prog_bram_csreg <= 4'b0010;
else if(ioctl_addr[9:8] == 2'd2) prog_bram_csreg <= 4'b0100; //wavetable 1(400-A 01)
else if(ioctl_addr[9:8] == 2'd3) prog_bram_csreg <= 4'b1000;
end
end
else begin
prog_bram_wr <= 1'b0;
end
end
// SDRAM REGION
else begin
prog_sdram_en <= 1'b1;
prog_bram_en <= 1'b0;
if(prog_sdram_wr_busy == 1'b0) begin
if(ioctl_wr == 1'b1) begin
prog_sdram_wr_busy <= 1'b1;
prog_sdram_bank_sel <= 2'd0;
prog_sdram_addr <= {4'b00_00, ioctl_addr[18:1]};
prog_sdram_din_buf <= {ioctl_data, ioctl_data};
prog_sdram_mask <= ioctl_addr[0] ? 2'b10 : 2'b01; //lo : hi(68k big endian)
end
end
else begin
if(prog_sdram_ack == 1'b1) begin
prog_sdram_wr_busy <= 1'b0;
end
end
end
end
else if(ioctl_index == 16'd254) begin //DIP SWITCH
prog_sdram_en <= 1'b0;
prog_bram_en <= 1'b0;
rom_download_done <= 1'b1;
end
end
end
///////////////////////////////////////////////////////////
////// BUBBLE MEMORY(BOOTLOADER)
////
wire [17:0] bubrom_addr;
wire bubrom_boot_cs;
wire [15:0] bubrom_boot_q;
reg [7:0] prog_bram_din_hi;
always @(posedge i_EMU_CLK72M) if(prog_bram_wr & ~prog_bram_addr[0]) prog_bram_din_hi <= prog_bram_din_buf;
BubSys_PROM_DC #(.AW(8), .DW(16), .simhexfile()) u_bootrom_lo (
.i_PROG_CLK (i_EMU_CLK72M ),
.i_PROG_ADDR (prog_bram_addr[8:1] ),
.i_PROG_DIN ({prog_bram_din_hi, prog_bram_din_buf}),
.i_PROG_CS (prog_bram_bootrom_cs ),
.i_PROG_WR (prog_bram_wr & prog_bram_addr[0]),
.i_MCLK (i_EMU_CLK48M ),
.i_ADDR (bubrom_addr[7:0] ),
.o_DOUT (bubrom_boot_q ),
.i_RD (bubrom_boot_cs )
);
///////////////////////////////////////////////////////////
////// SDRAM CONTROLLER
////
wire [21:0] ba0_addr;
wire [21:0] ba1_addr;
wire [21:0] ba2_addr;
wire [3:0] rd;
wire [3:0] ack;
wire [3:0] dst;
wire [3:0] rdy;
wire [15:0] data_read;
reg [8:0] rfsh_cntr;
wire rfsh = rfsh_cntr == 9'd384;
always @(posedge i_EMU_CLK72M) begin
if(i_EMU_INITRST) begin
rfsh_cntr <= 9'd0;
end
else begin if(o_VIDEO_CEN) begin
if(rfsh_cntr < 9'd384) rfsh_cntr <= rfsh_cntr + 9'd1;
else rfsh_cntr <= 9'd0;
end end
end
jtframe_sdram64 #(.HF(0)) sdram_controller (
.rst (i_EMU_INITRST ),
.clk (i_EMU_CLK72M ),
.init (sdram_init ),
.ba0_addr (ba0_addr ),
.ba1_addr (ba1_addr ),
.ba2_addr (22'h00_0000 ),
.ba3_addr (22'h00_0000 ),
.rd ({3'b000, rd[0]} ),
.wr (4'b0000 ),
.din (prog_sdram_din_buf ),
.din_m (2'b00 ),
.prog_en (prog_sdram_en ),
.prog_addr (prog_sdram_addr ),
.prog_rd (1'b0 ),
.prog_wr (prog_sdram_wr_busy ),
.prog_din (prog_sdram_din_buf ),
.prog_din_m (prog_sdram_mask ),
.prog_ba (prog_sdram_bank_sel ),
.prog_dst ( ),
.prog_dok ( ),
.prog_rdy ( ),
.prog_ack (prog_sdram_ack ),
.rfsh (rfsh ),
.ack (ack ),
.dst (dst ),
.dok ( ),
.rdy (rdy ),
.dout (data_read ),
.sdram_dq (sdram_dq ),
.sdram_a (sdram_a ),
.sdram_dqml (sdram_dqml ),
.sdram_dqmh (sdram_dqmh ),
.sdram_ba (sdram_ba ),
.sdram_nwe (sdram_nwe ),
.sdram_ncas (sdram_ncas ),
.sdram_nras (sdram_nras ),
.sdram_ncs (sdram_ncs ),
.sdram_cke (sdram_cke )
);
///////////////////////////////////////////////////////////
////// ROM SLOTS
////
wire bubrom_rd;
wire bubrom_page_cs;
wire [15:0] bubrom_page_q;
reg slot0_rdrq_z, slot0_rdrq_zz; //48MHz -> 72MHz
always @(posedge i_EMU_CLK72M) slot0_rdrq_z <= bubrom_rd & bubrom_page_cs;
always @(posedge i_EMU_CLK72M) slot0_rdrq_zz <= slot0_rdrq_z;
wire slot0_ok;
reg [3:0] slot0_ok_dly;
always @(posedge i_EMU_CLK72M) begin
slot0_ok_dly[0] <= slot0_ok;
slot0_ok_dly[3:1] <= slot0_ok_dly[2:0];
end
reg slot0_ok_z, slot0_ok_zz; //72MHz -> 48MHz
always @(posedge i_EMU_CLK48M) slot0_ok_z <= |{slot0_ok_dly[3:0]};
always @(posedge i_EMU_CLK48M) slot0_ok_zz <= slot0_ok_z;
jtframe_rom_2slots #(
// Slot 0: Bubble Memory user pages
.SLOT0_AW (18 ),
.SLOT0_DW (16 ),
.SLOT0_OFFSET (22'h00_0000 ),
// Slot 1: No ROM
.SLOT1_AW (4 ),
.SLOT1_DW (16 ),
.SLOT1_OFFSET (22'h02_0800 )
) bank0 (
.rst (~rom_download_done ),
.clk (i_EMU_CLK72M ),
.slot0_cs (slot0_rdrq_zz ),
.slot1_cs (1'b0 ),
.slot0_ok (slot0_ok ),
.slot1_ok ( ),
.slot0_addr (bubrom_addr ),
.slot1_addr (4'b0000 ),
.slot0_dout (bubrom_page_q ),
.slot1_dout ( ),
.sdram_addr (ba0_addr ),
.sdram_req (rd[0] ),
.sdram_ack (ack[0] ),
.data_dst (dst[0] ),
.data_rdy (rdy[0] ),
.data_read (data_read )
);
///////////////////////////////////////////////////////////
////// INPUT MAPPER
////
/*
MiSTer joystick(SNES)
bit
0 right
1 left
2 down
3 up
4 service(SELECT)
5 coin(R)
6 start(START)
7 btn1(A)
8 btn2(B)
9 btn3(X)
*/
wire [7:0] IN0, IN1, IN2;
//System control
assign IN0[0] = ~i_JOYSTICK0[5]; //p1 coin
assign IN0[1] = ~i_JOYSTICK1[5]; //p2 coin
assign IN0[2] = ~i_JOYSTICK0[4]; //service
assign IN0[3] = ~i_JOYSTICK0[6]; //p1 start
assign IN0[4] = ~i_JOYSTICK1[6]; //p2 start
assign IN0[5] = 1'b1;
assign IN0[6] = 1'b1;
assign IN0[7] = 1'b1;
//Player 1 control
assign IN1[0] = ~i_JOYSTICK0[1];
assign IN1[1] = ~i_JOYSTICK0[0];
assign IN1[2] = ~i_JOYSTICK0[3];
assign IN1[3] = ~i_JOYSTICK0[2];
assign IN1[4] = ~i_JOYSTICK0[7];
assign IN1[5] = ~i_JOYSTICK0[8];
assign IN1[6] = ~i_JOYSTICK0[9];
assign IN1[7] = 1'b1;
//Player 2 control
assign IN2[0] = ~i_JOYSTICK1[1];
assign IN2[1] = ~i_JOYSTICK1[0];
assign IN2[2] = ~i_JOYSTICK1[3];
assign IN2[3] = ~i_JOYSTICK1[2];
assign IN2[4] = ~i_JOYSTICK1[7]; //btn 1
assign IN2[5] = ~i_JOYSTICK1[8]; //btn 2
assign IN2[6] = ~i_JOYSTICK1[9];
assign IN2[7] = 1'b1;
///////////////////////////////////////////////////////////
////// GAME BOARD
////
reg [15:0] bubrom_data;
reg bubrom_data_rdy;
always @(*) begin
bubrom_data = 16'h0000;
if(bubrom_boot_cs) bubrom_data = bubrom_boot_q;
else if(bubrom_page_cs) bubrom_data = bubrom_page_q;
bubrom_data_rdy = 1'b0;
if(bubrom_boot_cs) bubrom_data_rdy = 1'b1;
else if(bubrom_page_cs) bubrom_data_rdy = slot0_ok_zz;
end
BubSys_top gameboard_top (
.i_EMU_CLK72M (i_EMU_CLK72M ),
.i_EMU_CLK57M (i_EMU_CLK57M ),
.i_EMU_CLK48M (i_EMU_CLK48M ),
.i_EMU_INITRST_n (~i_EMU_INITRST ),
.i_EMU_SOFTRST_n (~i_EMU_SOFTRST & rom_download_done),
.o_HBLANK (o_HBLANK ),
.o_VBLANK (o_VBLANK ),
.o_HSYNC (o_HSYNC ),
.o_VSYNC (o_VSYNC ),
.o_VIDEO_CEN (o_VIDEO_CEN ),
.o_VIDEO_DEN (o_VIDEO_DEN ),
.o_VIDEO_R (o_VIDEO_R ),
.o_VIDEO_G (o_VIDEO_G ),
.o_VIDEO_B (o_VIDEO_B ),
.i_VOL (i_VOL ),
.o_SND_L (o_SND_L ),
.o_SND_R (o_SND_R ),
.i_MAINCPU_SWAPIRQ (i_MAINCPU_SWAPIRQ ),
.o_BMC_ACC (o_BMC_ACC ),
.i_IN0 (IN0 ),
.i_IN1 (IN1 ),
.i_IN2 (IN2 ),
.i_DIPSW1 (DIPSW1 ),
.i_DIPSW2 (DIPSW2 ),
.i_DIPSW3 (DIPSW3 ),
//DRAM request, 48MHz
.o_BUBROM_BOOT_CS (bubrom_boot_cs ),
.o_BUBROM_PAGE_CS (bubrom_page_cs ),
.o_BUBROM_ADDR (bubrom_addr ),
.i_BUBROM_DATA (bubrom_data ),
.o_BUBROM_RD (bubrom_rd ),
.i_BUBROM_DATA_RDY (bubrom_data_rdy ),
//PROM programming
.i_EMU_PROM_ADDR (prog_bram_addr ),
.i_EMU_PROM_DATA (prog_bram_din_buf ),
.i_EMU_PROM_WR (prog_bram_wr ),
.i_EMU_PROM_WAVE1_CS (prog_bram_wave1_cs ),
.i_EMU_PROM_WAVE2_CS (prog_bram_wave2_cs ),
.i_EMU_PROM_SNDROM_CS (prog_bram_sndrom_cs )
);
endmodule

511
rtl/BubSys_sound.v Normal file
View File

@@ -0,0 +1,511 @@
module BubSys_sound (
input wire i_EMU_MCLK,
input wire i_EMU_CLK3M58_PCEN,
input wire i_EMU_CLK3M58_NCEN,
input wire i_EMU_CLK1M79_PCEN,
input wire i_EMU_CLK1M79_NCEN,
input wire i_EMU_INITRST_n,
input wire i_EMU_SOFTRST_n,
//reset control by the sound CPU
output wire o_MAINCPU_RSTCTRL,
input wire i_MAINCPU_RSTSTAT,
input wire i_SND_NMI,
input wire i_SND_INT,
input wire [7:0] i_SND_CODE,
input wire i_SND_DMA_BR,
output wire o_SND_DMA_BG_n,
input wire [14:1] i_SND_DMA_ADDR,
input wire [7:0] i_SND_DMA_DO,
output wire [7:0] o_SND_DMA_DI,
input wire i_SND_DMA_RnW,
input wire i_SND_DMA_LDS_n,
input wire i_SND_DMA_SNDRAM_CS,
output wire o_TIMER_IRQ,
input wire [15:0] i_VOL,
output wire signed [15:0] o_SND_R, o_SND_L,
input wire i_EMU_PROM_CLK,
input wire [13:0] i_EMU_PROM_ADDR,
input wire [7:0] i_EMU_PROM_DATA,
input wire i_EMU_PROM_WR,
input wire i_EMU_PROM_WAVE1_CS,
input wire i_EMU_PROM_WAVE2_CS,
input wire i_EMU_PROM_SNDROM_CS
);
///////////////////////////////////////////////////////////
////// CLOCK AND RESET
////
wire sndcpu_rst = ~i_EMU_INITRST_n | ~i_EMU_SOFTRST_n;
wire mclk = i_EMU_MCLK;
wire clk3m58_pcen = i_EMU_CLK3M58_PCEN;
wire clk3m58_ncen = i_EMU_CLK3M58_NCEN;
wire clk1m79_pcen = i_EMU_CLK1M79_PCEN;
wire clk1m79_ncen = i_EMU_CLK1M79_NCEN;
///////////////////////////////////////////////////////////
////// SOUND CPU
////
wire [15:0] sndcpu_addr;
reg [7:0] sndbus_di;
wire [7:0] sndcpu_do;
wire sndcpu_wr_n, sndcpu_rd_n;
wire sndcpu_mreq_n;
wire sndcpu_iorq_n;
wire sndcpu_rfsh_n;
reg sndcpu_int_n;
wire sndcpu_nmi_n;
wire sndcpu_br_n;
T80pa u_sndcpu (
.RESET_n (~sndcpu_rst ),
.CLK (mclk ),
.CEN_p (clk1m79_pcen ),
.CEN_n (clk1m79_ncen ),
.WAIT_n (1'b1 ),
.INT_n (sndcpu_int_n ),
.NMI_n (sndcpu_nmi_n ),
.RD_n (sndcpu_rd_n ),
.WR_n (sndcpu_wr_n ),
.A (sndcpu_addr ),
.DI (sndbus_di ),
.DO (sndcpu_do ),
.IORQ_n (sndcpu_iorq_n ),
.M1_n ( ),
.MREQ_n (sndcpu_mreq_n ),
.BUSRQ_n (sndcpu_br_n ),
.BUSAK_n (o_SND_DMA_BG_n ),
.RFSH_n (sndcpu_rfsh_n ),
.out0 (1'b0 ), //?????
.HALT_n ( )
);
///////////////////////////////////////////////////////////
////// DMA
////
reg [1:0] snd_dma_br_sync;
assign sndcpu_br_n = ~snd_dma_br_sync[1];
always @(posedge mclk) begin
snd_dma_br_sync[0] <= i_SND_DMA_BR;
snd_dma_br_sync[1] <= snd_dma_br_sync[0];
end
//68k bus control synchronizer/negedge detector <- CDC!!
reg [3:0] snd_dma_wr_n_sync, snd_dma_rd_n_sync;
reg snd_dma_wrrq_n, snd_dma_rdrq_n;
always @(posedge mclk) begin
//synchronize read/write strobe only, the address/data is guaranteed to be stable before the strobe is asserted
snd_dma_wr_n_sync[0] <= i_SND_DMA_RnW | i_SND_DMA_LDS_n;
snd_dma_wr_n_sync[3:1] <= snd_dma_wr_n_sync[2:0];
snd_dma_rd_n_sync[0] <= ~i_SND_DMA_RnW | i_SND_DMA_LDS_n;
snd_dma_rd_n_sync[3:1] <= snd_dma_rd_n_sync[2:0];
snd_dma_wrrq_n <= ~(snd_dma_wr_n_sync[3] && !snd_dma_wr_n_sync[2]);
snd_dma_rdrq_n <= ~(snd_dma_rd_n_sync[3] && !snd_dma_rd_n_sync[2]);
end
wire is_dma_acc = ~o_SND_DMA_BG_n;
wire [15:0] sndbus_addr = is_dma_acc ? {2'b01, i_SND_DMA_ADDR} : sndcpu_addr;
wire [7:0] sndbus_do = is_dma_acc ? i_SND_DMA_DO : sndcpu_do;
wire sndbus_wr_n = is_dma_acc ? snd_dma_wrrq_n : sndcpu_wr_n;
wire sndbus_rd_n = is_dma_acc ? snd_dma_rdrq_n : sndcpu_rd_n;
wire sndbus_mreq_n = is_dma_acc ? ~i_SND_DMA_SNDRAM_CS : sndcpu_mreq_n;
wire sndbus_rfsh_n = is_dma_acc ? 1'b1 : sndcpu_rfsh_n;
assign o_SND_DMA_DI = sndbus_di;
///////////////////////////////////////////////////////////
////// SOUND IRQ
////
reg [3:0] snd_int_sync; //CDC!!!
reg [1:0] snd_nmi_sync;
assign sndcpu_nmi_n = ~snd_nmi_sync[1];
always @(posedge mclk) begin
snd_int_sync[0] <= i_SND_INT;
snd_int_sync[3:1] <= snd_int_sync[2:0];
if(sndcpu_rst | ~sndcpu_iorq_n) sndcpu_int_n <= 1'b1;
else begin
if(snd_int_sync[3:2] == 2'b01) sndcpu_int_n <= 1'b0;
end
snd_nmi_sync[0] <= i_SND_NMI;
snd_nmi_sync[1] <= snd_nmi_sync[0];
end
///////////////////////////////////////////////////////////
////// ADDRESS DECODER
////
reg sndrom_rd, sndram_cs, voiceram_cs, wave1_wr, wave2_wr;
reg vlmctrl_wr, sndcode_rd, wave1_tg, wave2_tg, psg1_cs, psg2_cs, fltctrl_wr;
always @(*) begin
sndrom_rd = 1'b0;
sndram_cs = 1'b0;
voiceram_cs = 1'b0;
wave1_wr = 1'b0;
wave2_wr = 1'b0;
vlmctrl_wr = 1'b0;
sndcode_rd = 1'b0;
wave1_tg = 1'b0;
wave2_tg = 1'b0;
psg1_cs = 1'b0;
psg2_cs = 1'b0;
fltctrl_wr = 1'b0;
//1st LS138
if(!sndbus_mreq_n && sndbus_rfsh_n) begin
case(sndbus_addr[15:13])
3'd0: sndrom_rd = 1'b1;
3'd2: sndram_cs = 1'b1;
3'd3: sndram_cs = 1'b1;
3'd4: voiceram_cs = 1'b1;
3'd5: wave1_wr = 1'b1;
3'd6: wave2_wr = 1'b1;
default: ;
endcase
end
//2nd LS138
if(!sndbus_mreq_n && sndbus_rfsh_n && sndbus_addr[15:13] == 3'd7) begin
case(sndbus_addr[2:0])
3'd0: vlmctrl_wr = 1'b1;
3'd1: sndcode_rd = 1'b1;
3'd3: wave1_tg = 1'b1;
3'd4: wave2_tg = 1'b1;
3'd5: psg2_cs = 1'b1;
3'd6: psg1_cs = 1'b1;
3'd7: fltctrl_wr = 1'b1;
default: ;
endcase
end
end
///////////////////////////////////////////////////////////
////// SOUND PROGRAM SPACE
////
wire [7:0] sndrom_q;
BubSys_PROM_DC #(.AW(13), .DW(8), .simhexfile()) u_sndrom (
.i_PROG_CLK (i_EMU_PROM_CLK ),
.i_PROG_ADDR (i_EMU_PROM_ADDR[12:0] ),
.i_PROG_DIN (i_EMU_PROM_DATA ),
.i_PROG_CS (i_EMU_PROM_SNDROM_CS ),
.i_PROG_WR (i_EMU_PROM_WR ),
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (sndbus_addr[12:0] ),
.o_DOUT (sndrom_q ),
.i_RD (sndrom_rd )
);
wire [7:0] sndram_q;
BubSys_SRAM #(.AW(14), .DW(8), .simhexfile()) u_sndram (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (sndbus_addr[13:0] ),
.i_DIN (sndbus_do ),
.o_DOUT (sndram_q ),
.i_WR (sndram_cs && !sndbus_wr_n ),
.i_RD (sndram_cs && !sndbus_rd_n )
);
///////////////////////////////////////////////////////////
////// SOUND TIMER
////
//14.31818MHz clocked four LS393 half blocks, take [13:0] MSBs
reg [12:0] snd_timer;
always @(posedge mclk) begin
//if(sndcpu_rst) snd_timer <= 13'd0; //doesn't have reset originally
//else begin
if(clk1m79_ncen) snd_timer <= snd_timer == 13'd8191 ? 13'd0 : snd_timer + 13'd1;
//end end
end
assign o_TIMER_IRQ = snd_timer[12];
///////////////////////////////////////////////////////////
////// VLM5030
////
//VLM5030 control latches
reg [7:0] vlm_param_latch; //LS373 transparent latch
reg [3:0] vlm_ctrl_latch = 4'b0010; //{vlm_rst, vlm_start, /vlm_param_latch_oe, vlm_param_latch_en}
always @(posedge mclk) begin
if(vlmctrl_wr && !sndbus_wr_n) vlm_ctrl_latch <= sndbus_addr[6:3];
if(vlm_ctrl_latch[0]) vlm_param_latch <= sndbus_do;
end
//VLM5030 side wires
wire vlm_rst = vlm_ctrl_latch[3];
wire vlm_st = vlm_ctrl_latch[2];
wire vlm_busy;
wire [15:0] vlm_addr;
wire vlm_me_n; //Memory Enable
wire signed [9:0] vlm_sound;
//VLM5030 command rom
wire [10:0] voiceram_addr = voiceram_cs ? sndbus_addr[10:0] : vlm_addr[10:0];
wire [7:0] voiceram_q;
BubSys_SRAM #(.AW(11), .DW(8), .simhexfile()) u_voiceram (
.i_MCLK (i_EMU_MCLK ),
.i_ADDR (voiceram_addr ),
.i_DIN (vlm_param_latch ),
.o_DOUT (voiceram_q ),
.i_WR (voiceram_cs && !sndbus_wr_n),
.i_RD (1'b1 )
);
//VLM5030 bus
wire [7:0] vlm_di = vlm_me_n ? vlm_param_latch : voiceram_q; //negative logic
//main chip
vlm5030_gl u_vlm (
.i_clk (i_EMU_MCLK ),
.i_oscen (clk3m58_pcen ),
.i_rst (vlm_rst ),
.i_start (vlm_st ),
.i_vcu (1'b0 ),
.i_tst1 (1'b0 ),
.i_d (vlm_di ),
.o_a (vlm_addr ),
.o_me_l (vlm_me_n ),
.o_bsy (vlm_busy ),
.o_audio (vlm_sound )
);
///////////////////////////////////////////////////////////
////// AY-3-8910
////
wire [7:0] psg1_q, psg2_q;
wire [7:0] psg1_iob_out, psg2_ioa_out, psg2_iob_out;
wire [9:0] psg1_sound, psg2_sound;
assign o_MAINCPU_RSTCTRL = ~psg1_iob_out[7];
//MAME PSG1(4F on the board)
jt49_bus u_psg1 (
.rst_n (~sndcpu_rst ),
.clk (mclk ),
.clk_en (clk1m79_pcen ),
.bdir (psg1_cs & (~sndcpu_rd_n | ~sndcpu_wr_n) & ~sndbus_addr[7]),
.bc1 (psg1_cs & (~sndcpu_rd_n | ~sndcpu_wr_n) & ~sndbus_addr[8]),
.din (sndbus_do ),
.sel (1'b1 ),
.dout (psg1_q ),
.sound (psg1_sound ),
.A ( ),
.B ( ),
.C ( ),
.sample ( ),
.IOA_in ({~i_MAINCPU_RSTSTAT, 1'b1, vlm_busy, 1'b1, snd_timer[12:9]}),
.IOA_out ( ),
.IOA_oe ( ),
.IOB_in ( ),
.IOB_out (psg1_iob_out ),
.IOB_oe ( )
);
//MAME PSG2(4H on the board)
jt49_bus u_psg2 (
.rst_n (~sndcpu_rst ),
.clk (mclk ),
.clk_en (clk1m79_pcen ),
.bdir (psg2_cs & (~sndcpu_rd_n | ~sndcpu_wr_n) & ~sndbus_addr[9]),
.bc1 (psg2_cs & (~sndcpu_rd_n | ~sndcpu_wr_n) & ~sndbus_addr[10]),
.din (sndbus_do ),
.sel (1'b1 ),
.dout (psg2_q ),
.sound (psg2_sound ),
.A ( ),
.B ( ),
.C ( ),
.sample ( ),
.IOA_in ( ),
.IOA_out (psg2_ioa_out ),
.IOA_oe ( ),
.IOB_in ( ),
.IOB_out (psg2_iob_out ),
.IOB_oe ( )
);
///////////////////////////////////////////////////////////
////// K005289 WAVETABLE
////
wire [4:0] prom1_addr, prom2_addr;
wire [3:0] prom1_q, prom2_q;
wire [7:0] wave1_sound, wave2_sound;
//wavetable address generator
K005289 u_K005289(
.i_RST_n (~sndcpu_rst ),
.i_CLK (mclk ),
.i_CEN (clk3m58_pcen ),
.i_LD1 (wave1_wr ),
.i_TG1 (wave1_tg ),
.i_LD2 (wave2_wr ),
.i_TG2 (wave2_tg ),
.i_COUNTER (sndbus_addr[11:0] ),
.o_Q1 (prom1_addr ),
.o_Q2 (prom2_addr )
);
//wavetable ROMs
BubSys_PROM_DC #(.AW(8), .DW(4), .simhexfile()) u_waverom1 (
.i_PROG_CLK (i_EMU_PROM_CLK ),
.i_PROG_ADDR (i_EMU_PROM_ADDR[7:0] ),
.i_PROG_DIN (i_EMU_PROM_DATA[3:0] ),
.i_PROG_CS (i_EMU_PROM_WAVE1_CS ),
.i_PROG_WR (i_EMU_PROM_WR ),
.i_MCLK (i_EMU_MCLK ),
.i_ADDR ({psg2_ioa_out[7:5], prom1_addr}),
.o_DOUT (prom1_q ),
.i_RD (1'b1 )
);
BubSys_PROM_DC #(.AW(8), .DW(4), .simhexfile()) u_waverom2 (
.i_PROG_CLK (i_EMU_PROM_CLK ),
.i_PROG_ADDR (i_EMU_PROM_ADDR[7:0] ),
.i_PROG_DIN (i_EMU_PROM_DATA[3:0] ),
.i_PROG_CS (i_EMU_PROM_WAVE2_CS ),
.i_PROG_WR (i_EMU_PROM_WR ),
.i_MCLK (i_EMU_MCLK ),
.i_ADDR ({psg2_iob_out[7:5], prom2_addr}),
.o_DOUT (prom2_q ),
.i_RD (1'b1 )
);
//volume LUT, replaces 4066 switches
BubSys_PROM #(.AW(8), .DW(8), .simhexfile("./rtl/ipcores/vollut.txt")) u_vollut1 (
.i_MCLK (i_EMU_MCLK ),
.i_PROG_ADDR ( ),
.i_PROG_DIN ( ),
.i_PROG_CS (1'b1 ),
.i_PROG_WR ( ),
.i_ADDR ({psg2_ioa_out[3:0], prom1_q}),
.o_DOUT (wave1_sound ),
.i_RD (1'b1 )
);
BubSys_PROM #(.AW(8), .DW(8), .simhexfile("./rtl/ipcores/vollut.txt")) u_vollut2 (
.i_MCLK (i_EMU_MCLK ),
.i_PROG_ADDR ( ),
.i_PROG_DIN ( ),
.i_PROG_CS (1'b1 ),
.i_PROG_WR ( ),
.i_ADDR ({psg2_iob_out[3:0], prom2_q}),
.o_DOUT (wave2_sound ),
.i_RD (1'b1 )
);
///////////////////////////////////////////////////////////
////// SOUND MIXER
////
/*
psg_sound = 10-bit unsigned
vlm_sound = 10-bit signed
wavex_sound = 8-bit(normally 7-bit) unsigned
*/
wire signed [9:0] psg1_sound_ac, psg2_sound_ac;
jt49_dcrm2 #(.sw(10)) psg1_accap (.clk(mclk), .cen(clk3m58_pcen), .rst(sndcpu_rst), .din(psg1_sound), .dout(psg1_sound_ac));
jt49_dcrm2 #(.sw(10)) psg2_accap (.clk(mclk), .cen(clk3m58_pcen), .rst(sndcpu_rst), .din(psg2_sound), .dout(psg2_sound_ac));
wire signed [7:0] wave1_sound_ac, wave2_sound_ac;
jt49_dcrm2 #(.sw(8)) wave1_accap (.clk(mclk), .cen(clk3m58_pcen), .rst(sndcpu_rst), .din(wave1_sound), .dout(wave1_sound_ac));
jt49_dcrm2 #(.sw(8)) wave2_accap (.clk(mclk), .cen(clk3m58_pcen), .rst(sndcpu_rst), .din(wave2_sound), .dout(wave2_sound_ac));
reg signed [13:0] psg1_sound_vol, psg2_sound_vol;
reg signed [13:0] vlm_sound_vol;
reg signed [13:0] wave1_sound_vol, wave2_sound_vol;
reg signed [15:0] final_sound;
assign o_SND_L = final_sound;
assign o_SND_R = final_sound;
always @(posedge mclk) begin
psg1_sound_vol <= psg1_sound_ac * (6'sd8 + $signed(i_VOL[11:8]));
psg2_sound_vol <= psg2_sound_ac * (6'sd12 + $signed(i_VOL[15:12]));
vlm_sound_vol <= vlm_sound * (6'sd10 + $signed(i_VOL[7:4]));
wave1_sound_vol <= wave1_sound_ac * (6'sd8 + $signed(i_VOL[3:0]));
wave2_sound_vol <= wave2_sound_ac * (6'sd8 + $signed(i_VOL[3:0]));
final_sound <= (psg1_sound_vol + psg2_sound_vol + vlm_sound_vol + wave1_sound_vol + wave2_sound_vol) * 3'sd2;
end
///////////////////////////////////////////////////////////
////// BUS MUX
////
always @(*) begin
sndbus_di = 8'hFF;
if(sndrom_rd) begin
sndbus_di = sndrom_q;
end
else if(sndram_cs) sndbus_di = sndram_q;
else if(sndcode_rd) sndbus_di = i_SND_CODE;
else if(psg1_cs) sndbus_di = psg1_q;
else if(psg2_cs) sndbus_di = psg2_q;
end
endmodule

351
rtl/BubSys_top.v Normal file
View File

@@ -0,0 +1,351 @@
module BubSys_top (
input wire i_EMU_CLK72M,
input wire i_EMU_CLK57M,
input wire i_EMU_CLK48M,
input wire i_EMU_INITRST_n,
input wire i_EMU_SOFTRST_n,
//video syncs
output reg o_HBLANK, //NOT the original blanking signal
output wire o_VBLANK,
output wire o_HSYNC,
output wire o_VSYNC,
output wire o_VIDEO_CEN, //video clock enable
output wire o_VIDEO_DEN, //video data enable
output wire [4:0] o_VIDEO_R,
output wire [4:0] o_VIDEO_G,
output wire [4:0] o_VIDEO_B,
//sound
input wire [15:0] i_VOL,
output wire signed [15:0] o_SND_L,
output wire signed [15:0] o_SND_R,
//configuration
input wire i_MAINCPU_SWAPIRQ,
output wire o_BMC_ACC,
//user inputs
input wire [7:0] i_IN0, i_IN1, i_IN2, i_DIPSW1, i_DIPSW2, i_DIPSW3,
//SDRAM requests
output wire o_BUBROM_BOOT_CS, o_BUBROM_PAGE_CS,
output wire [17:0] o_BUBROM_ADDR,
input wire [15:0] i_BUBROM_DATA,
output wire o_BUBROM_RD,
input wire i_BUBROM_DATA_RDY,
//PROM programming
input wire [13:0] i_EMU_PROM_ADDR,
input wire [7:0] i_EMU_PROM_DATA,
input wire i_EMU_PROM_WR,
input wire i_EMU_PROM_WAVE1_CS,
input wire i_EMU_PROM_WAVE2_CS,
input wire i_EMU_PROM_SNDROM_CS
);
///////////////////////////////////////////////////////////
////// CLOCK DIVIDER
////
/*
0 4 8 12 16 20
CLK18M _|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|
CLK9M ¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|
CLK6M ¯¯¯¯¯¯¯|___|¯¯¯¯¯¯¯|___|¯¯¯¯¯¯¯|___|¯¯¯¯¯¯¯|___|
*/
reg [3:0] clk18m_cen_sr = 4'd1;
reg [7:0] clk9m_cen_sr = 8'd1;
reg [11:0] clk6m_cen_sr = 12'd1;
always @(posedge i_EMU_CLK72M) begin
if(!i_EMU_INITRST_n) begin
clk18m_cen_sr <= 4'd1;
clk9m_cen_sr <= 8'd1;
clk6m_cen_sr <= 12'd1;
end
else begin
clk18m_cen_sr[3:1] <= clk18m_cen_sr[2:0];
clk18m_cen_sr[0] <= clk18m_cen_sr[3];
clk9m_cen_sr[7:1] <= clk9m_cen_sr[6:0];
clk9m_cen_sr[0] <= clk9m_cen_sr[7];
clk6m_cen_sr[11:1] <= clk6m_cen_sr[10:0];
clk6m_cen_sr[0] <= clk6m_cen_sr[11];
end
end
//clock enables, generated by shift register(for better performance);
wire clk18m_ncen = clk18m_cen_sr[3];
wire clk9m_ncen = clk9m_cen_sr[3];
wire clk9m_pcen = clk9m_cen_sr[7];
wire clk6m_ncen = clk6m_cen_sr[7];
wire clk6m_pcen = clk6m_cen_sr[11];
//sound clock
reg [4:0] snd_cen_cntr = 5'd0;
reg clk3m58_ncen, clk3m58_pcen;
reg clk1m79_ncen, clk1m79_pcen;
always @(posedge i_EMU_CLK57M) begin
if(!i_EMU_INITRST_n) snd_cen_cntr <= 5'd0;
else snd_cen_cntr <= snd_cen_cntr == 5'd31 ? 5'd0 : snd_cen_cntr + 5'd1;
if(!i_EMU_INITRST_n) begin
clk3m58_pcen <= 1'b0;
clk3m58_ncen <= 1'b0;
clk1m79_pcen <= 1'b0;
clk1m79_ncen <= 1'b0;
end
else begin
clk3m58_pcen <= snd_cen_cntr[3:0] == 4'd6;
clk3m58_ncen <= snd_cen_cntr[3:0] == 4'd14;
clk1m79_pcen <= snd_cen_cntr == 5'd14;
clk1m79_ncen <= snd_cen_cntr == 5'd30;
end
end
reg debug_clk9m, debug_clk6m;
always @(posedge i_EMU_CLK72M) begin
if(clk9m_ncen) debug_clk9m <= 1'b0;
else if(clk9m_pcen) debug_clk9m <= 1'b1;
if(clk6m_ncen) debug_clk6m <= 1'b0;
else if(clk6m_pcen) debug_clk6m <= 1'b1;
end
reg debug_clk3m58, debug_clk1m79;
always @(posedge i_EMU_CLK57M) begin
if(clk3m58_ncen) debug_clk3m58 <= 1'b0;
else if(clk3m58_pcen) debug_clk3m58 <= 1'b1;
if(clk1m79_ncen) debug_clk1m79 <= 1'b0;
else if(clk1m79_pcen) debug_clk1m79 <= 1'b1;
end
///////////////////////////////////////////////////////////
////// BOARD INTERCONNECTION
////
wire maincpu_rstctrl, maincpu_rststat;
wire gfx_scrollram_cs, gfx_videoram_cs, gfx_colorram_cs, gfx_charram_cs, gfx_objram_cs;
wire [14:0] gfx_addr;
wire [15:0] gfx_do, gfx_di;
wire gfx_r_nw, gfx_uds_n, gfx_lds_n;
wire abs_1h_n, abs_2h, abs_32h, gfx_frameparity;
wire gfx_hflip, gfx_vflip;
wire gfx_blk;
wire [10:0] gfx_cd;
wire gfx_hblank_n, gfx_vblank_n, gfx_vsync_n, gfx_hsync_n;
wire [7:0] snd_code;
wire snd_nmi, snd_int;
wire snd_dma_br, snd_dma_bg_n;
wire [14:1] snd_dma_addr;
wire [7:0] snd_dma_do, snd_dma_di;
wire snd_dma_r_nw, snd_dma_lds_n;
wire snd_dma_sndram_cs;
wire timer_irq;
assign o_VBLANK = ~gfx_vblank_n;
assign o_HSYNC = ~gfx_hsync_n;
assign o_VSYNC = ~gfx_vsync_n;
assign o_VIDEO_CEN = clk6m_pcen;
assign o_VIDEO_DEN = gfx_blk;
wire [15:0] debug_video = {1'b0, o_VIDEO_B, o_VIDEO_G, o_VIDEO_R};
wire [8:0] hcounter;
wire [8:0] vcounter;
///////////////////////////////////////////////////////////
////// CPU BOARD
////
BubSys_cpu u_cpuboard (
.i_EMU_MCLK (i_EMU_CLK72M ),
.i_EMU_CLK9M_PCEN (clk9m_pcen ),
.i_EMU_CLK9M_NCEN (clk9m_ncen ),
.i_EMU_CLK6M_PCEN (clk6m_pcen ),
.i_EMU_CLK6M_NCEN (clk6m_ncen ),
.i_EMU_INITRST_n (i_EMU_INITRST_n ),
.i_EMU_SOFTRST_n (i_EMU_SOFTRST_n ),
.i_MAINCPU_RSTCTRL (maincpu_rstctrl ),
.o_MAINCPU_RSTSTAT (maincpu_rststat ),
.i_MAINCPU_SWAPIRQ (i_MAINCPU_SWAPIRQ ),
.i_BMC_MCLK (i_EMU_CLK48M ),
.i_BMC_TEMPLO_n (1'b1 ),
.o_BMC_ACC (o_BMC_ACC ),
.o_GFX_ADDR (gfx_addr ),
.i_GFX_DO (gfx_do ),
.o_GFX_DI (gfx_di ),
.o_GFX_RnW (gfx_r_nw ),
.o_GFX_UDS_n (gfx_uds_n ),
.o_GFX_LDS_n (gfx_lds_n ),
.o_VZCS_n (gfx_scrollram_cs ),
.o_VCS1_n (gfx_videoram_cs ),
.o_VCS2_n (gfx_colorram_cs ),
.o_CHACS_n (gfx_charram_cs ),
.o_OBJRAM_n (gfx_objram_cs ),
.o_HFLIP (gfx_hflip ),
.o_VFLIP (gfx_vflip ),
.i_ABS_1H_n (abs_1h_n ),
.i_ABS_2H (abs_2h ),
.i_ABS_32H (abs_32h ),
.i_VBLANK_n (gfx_vblank_n ), //470pF+LS244 10ns? delay
.i_FRAMEPARITY (gfx_frameparity ), //same as above
.i_BLK (gfx_blk ),
.i_CD (gfx_cd ),
.o_SND_INT (snd_int ),
.o_SND_NMI (snd_nmi ),
.o_SND_CODE (snd_code ),
.o_SND_DMA_BR (snd_dma_br ),
.i_SND_DMA_BG_n (snd_dma_bg_n ),
.o_SND_DMA_ADDR (snd_dma_addr ),
.o_SND_DMA_DO (snd_dma_do ),
.i_SND_DMA_DI (snd_dma_di ),
.o_SND_DMA_RnW (snd_dma_r_nw ),
.o_SND_DMA_LDS_n (snd_dma_lds_n ),
.o_SND_DMA_SNDRAM_CS (snd_dma_sndram_cs ),
.i_TIMER_IRQ (timer_irq ),
.i_IN0 (i_IN0 ),
.i_IN1 (i_IN1 ),
.i_IN2 (i_IN2 ),
.i_DIPSW1 (i_DIPSW1 ),
.i_DIPSW2 (i_DIPSW2 ),
.i_DIPSW3 (i_DIPSW3 ),
.o_VIDEO_R (o_VIDEO_R ),
.o_VIDEO_G (o_VIDEO_G ),
.o_VIDEO_B (o_VIDEO_B ),
.o_BUBROM_BOOT_CS (o_BUBROM_BOOT_CS ),
.o_BUBROM_PAGE_CS (o_BUBROM_PAGE_CS ),
.o_BUBROM_ADDR (o_BUBROM_ADDR ),
.i_BUBROM_DATA (i_BUBROM_DATA ),
.o_BUBROM_RD (o_BUBROM_RD ),
.i_BUBROM_DATA_RDY (i_BUBROM_DATA_RDY )
);
///////////////////////////////////////////////////////////
////// VIDEO BOARD
////
GX400_video u_gx400_video (
.i_EMU_MCLK (i_EMU_CLK72M ),
.i_EMU_CLK18M_NCEN (clk18m_ncen ),
.i_EMU_CLK6M_PCEN (clk6m_pcen ),
.i_EMU_CLK6M_NCEN (clk6m_ncen ),
.i_MRST_n (i_EMU_INITRST_n ),
.i_GFX_ADDR (gfx_addr ),
.o_GFX_DO (gfx_do ),
.i_GFX_DI (gfx_di ),
.i_GFX_RnW (gfx_r_nw ),
.i_GFX_UDS_n (gfx_uds_n ),
.i_GFX_LDS_n (gfx_lds_n ),
.i_VZCS_n (gfx_scrollram_cs ),
.i_VCS1_n (gfx_videoram_cs ),
.i_VCS2_n (gfx_colorram_cs ),
.i_CHACS_n (gfx_charram_cs ),
.i_OBJRAM_n (gfx_objram_cs ),
.i_HFLIP (gfx_hflip ),
.i_VFLIP (gfx_vflip ),
.o_HBLANK_n (gfx_hblank_n ),
.o_VBLANK_n (gfx_vblank_n ),
.o_HSYNC_n (gfx_hsync_n ),
.o_VSYNC_n (gfx_vsync_n ),
.o_ABS_1H_n (abs_1h_n ),
.o_ABS_2H (abs_2h ),
.o_ABS_32H (abs_32h ),
.o_FRAMEPARITY (gfx_frameparity ),
.o_BLK (gfx_blk ),
.o_CD (gfx_cd ),
.o_DEBUG_HCNTR (hcounter ),
.o_DEBUG_VCNTR (vcounter )
);
always @(posedge i_EMU_CLK72M) begin
if(!i_EMU_INITRST_n) begin
o_HBLANK <= 1'b0;
end
else begin if(clk6m_pcen) begin
if(hcounter == 9'd149) o_HBLANK <= 1'b1;
else if(hcounter == 9'd277) o_HBLANK <= 1'b0;
end end
end
///////////////////////////////////////////////////////////
////// SOUND SECTION
////
BubSys_sound u_sound (
.i_EMU_MCLK (i_EMU_CLK57M ),
.i_EMU_CLK3M58_PCEN (clk3m58_pcen ),
.i_EMU_CLK3M58_NCEN (clk3m58_ncen ),
.i_EMU_CLK1M79_PCEN (clk1m79_pcen ),
.i_EMU_CLK1M79_NCEN (clk1m79_ncen ),
.i_EMU_INITRST_n (i_EMU_INITRST_n ),
.i_EMU_SOFTRST_n (i_EMU_SOFTRST_n ),
.o_MAINCPU_RSTCTRL (maincpu_rstctrl ),
.i_MAINCPU_RSTSTAT (maincpu_rststat ),
.i_SND_INT (snd_int ),
.i_SND_NMI (snd_nmi ),
.i_SND_CODE (snd_code ),
.i_SND_DMA_BR (snd_dma_br ),
.o_SND_DMA_BG_n (snd_dma_bg_n ),
.i_SND_DMA_ADDR (snd_dma_addr ),
.i_SND_DMA_DO (snd_dma_do ),
.o_SND_DMA_DI (snd_dma_di ),
.i_SND_DMA_RnW (snd_dma_r_nw ),
.i_SND_DMA_LDS_n (snd_dma_lds_n ),
.i_SND_DMA_SNDRAM_CS (snd_dma_sndram_cs ),
.o_TIMER_IRQ (timer_irq ),
.i_VOL (i_VOL ),
.o_SND_L (o_SND_L ),
.o_SND_R (o_SND_R ),
.i_EMU_PROM_CLK (i_EMU_CLK72M ),
.i_EMU_PROM_ADDR (i_EMU_PROM_ADDR ),
.i_EMU_PROM_DATA (i_EMU_PROM_DATA ),
.i_EMU_PROM_WR (i_EMU_PROM_WR ),
.i_EMU_PROM_WAVE1_CS (i_EMU_PROM_WAVE1_CS ),
.i_EMU_PROM_WAVE2_CS (i_EMU_PROM_WAVE2_CS ),
.i_EMU_PROM_SNDROM_CS (i_EMU_PROM_SNDROM_CS )
);
endmodule

View File

@@ -0,0 +1,9 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) GX400_video.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) GX400_video_sram.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) GX400_video_dram.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005290.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005291.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005292.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005293.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005294.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) K005295.v ]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/*
DRAM
*/
module GX400_video_dram #( parameter
dw=8, // data width
aw=8, // address bus width (number of pins)
rw=aw, // row width (usually address but width)
cw=aw, // column width (address but width or shorter)
ctop=cw-1, // index in address where MSB of col is
cbot=0, // index in address where LSB of col is
simhexfile="",
init=0
)
(
input wire i_MCLK,
input wire [aw-1:0] i_ADDR,
input wire [dw-1:0] i_DIN,
output reg [dw-1:0] o_DOUT,
input wire i_RAS_n,
input wire i_CAS_n,
input wire i_WR_n,
input wire i_RD_n
);
reg [dw-1:0] RAM [0:(2**(rw+cw))-1];
reg prev_ras;
reg prev_cas;
reg [rw-1:0] ROW_ADDR;
reg [cw-1:0] COL_ADDR;
wire [rw+cw-1:0] ADDR = {COL_ADDR, ROW_ADDR};
wire valid_n = prev_cas | i_RAS_n;
always @(posedge i_MCLK)
begin
prev_ras <= i_RAS_n;
prev_cas <= i_CAS_n;
if(i_RAS_n == 1'b0 && prev_ras == 1'b1)
begin
ROW_ADDR <= i_ADDR;
end
if(i_CAS_n == 1'b0 && prev_cas == 1'b1)
begin
COL_ADDR <= i_ADDR[ctop:cbot];
end
end
always @(posedge i_MCLK) begin
if(!valid_n) begin
if(!i_WR_n) RAM[ADDR] <= i_DIN;
else o_DOUT <= RAM[ADDR];
end
end
integer i;
initial
begin
if( simhexfile != "" )
begin
$readmemh(simhexfile, RAM);
end
end
endmodule

View File

@@ -0,0 +1,72 @@
module GX400_video_sim
(
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
input wire [8:0] i_HCOUNTER,
input wire [8:0] i_VCOUNTER,
input wire [15:0] i_VIDEODATA
);
/*
VCNTR
272 - HCNTR 278~511 + 128~149; 150 end of line
~
495 - HCNTR 278~511 + 128~149; 150 end of frame
*/
reg [7:0] RESNET_CONSTANT[31:0];
reg [7:0] BITMAP_HEADER[63:0];
integer BITMAP_LINE_ADDRESS = 32'h29D36;
wire [4:0] B = i_VIDEODATA[14:10];
wire [4:0] G = i_VIDEODATA[9:5];
wire [4:0] R = i_VIDEODATA[4:0];
integer fd;
integer i;
reg [15:0] frame = 16'd0;
initial begin
$readmemh("./GX400_video/debug_resnet_level.txt", RESNET_CONSTANT);
$readmemh("./GX400_video/debug_bitmap_header.txt", BITMAP_HEADER);
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_VCOUNTER > 9'd271 && i_VCOUNTER < 9'd496) begin
if (i_VCOUNTER == 9'd272 && i_HCOUNTER == 9'd276) begin
BITMAP_LINE_ADDRESS = 20'h29D36; //reset line
fd = $fopen($sformatf("./vsim/gx400_frame%0d.bmp", frame), "wb"); //generate new file
for(i = 0; i < 54; i = i + 1) begin //write bitmap header
$fwrite(fd, "%c", BITMAP_HEADER[i]);
end
$display("Start of frame %d", frame); //debug message
end
else if(i_HCOUNTER == 9'd277) begin
$fseek(fd, BITMAP_LINE_ADDRESS, 0); //set current line address
end
else if(i_HCOUNTER > 9'd277 || i_HCOUNTER < 9'd150) begin
$fwrite(fd, "%c%c%c", RESNET_CONSTANT[B], RESNET_CONSTANT[G], RESNET_CONSTANT[R]); //B G R
end
else if(i_HCOUNTER == 9'd150) begin
BITMAP_LINE_ADDRESS = BITMAP_LINE_ADDRESS - 32'h300; //decrease line
end
else if(i_VCOUNTER == 9'd495 && i_HCOUNTER == 9'd151) begin
$fclose(fd); //close this frame
$display("Frame %d saved", frame); //debug message
frame = frame + 16'd1;
end
else begin
end
end
end
end
endmodule

View File

@@ -0,0 +1,44 @@
/*
SRAM
*/
module GX400_video_sram #(parameter
dw=8,
aw=10,
simhexfile=""
)
(
input wire i_MCLK,
input wire [aw-1:0] i_ADDR,
input wire [dw-1:0] i_DIN,
output reg [dw-1:0] o_DOUT,
input wire i_WR_n,
input wire i_RD_n
);
reg [dw-1:0] RAM [0:(2**aw)-1];
always @(posedge i_MCLK)
begin
if(i_WR_n == 1'b0)
begin
RAM[i_ADDR] <= i_DIN;
end
end
always @(posedge i_MCLK) //read
begin
if(i_RD_n == 1'b0)
begin
o_DOUT <= RAM[i_ADDR];
end
end
initial
begin
if( simhexfile != "" ) begin
$readmemh(simhexfile, RAM);
end
end
endmodule

228
rtl/GX400_video/K005290.v Normal file
View File

@@ -0,0 +1,228 @@
/*
tilemapsr TILEMAP SHIFT REGISTER ARRAY
*/
module K005290 (
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
//pixel data
input wire [31:0] i_GFXDATA,
//hcounter
input wire i_ABS_n4H,
input wire i_ABS_2H,
//flips
input wire i_AFF,
input wire i_BFF,
//sr mode
input wire [1:0] i_A_MODE,
input wire [1:0] i_B_MODE,
//pixel output
output reg [3:0] o_A_PIXEL,
output reg [3:0] o_B_PIXEL,
//pixel transparent flag
output wire o_A_TRN_n,
output wire o_B_TRN_n
);
///////////////////////////////////////////////////////////
////// TILELINE LATCH
////
/*
pixel 0 1 2 3 4 5 6 7
1H _|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|
2H ___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|___|¯¯¯|
/4H ¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
4H _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|
*/
reg ABS_2H_dl;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
ABS_2H_dl <= i_ABS_2H;
end
end
wire pixel3_n = ~(i_ABS_2H & ABS_2H_dl & i_ABS_n4H);
wire pixel7_n = ~(i_ABS_2H & ABS_2H_dl & ~i_ABS_n4H);
//
// tileline latches
//
reg [31:0] A_TILELINELATCH;
reg [31:0] B_TILELINELATCH;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(!pixel7_n) begin //posedge of px7
A_TILELINELATCH <= i_GFXDATA;
end
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(!pixel3_n) begin //posedge of px3
B_TILELINELATCH <= i_GFXDATA;
end
end
end
///////////////////////////////////////////////////////////
////// PIXEL SHIFT REGISTER
////
//
// TM-A shift register
//
reg [3:0] A_PIXEL0 = 4'h0;
reg [3:0] A_PIXEL1 = 4'h0;
reg [3:0] A_PIXEL2 = 4'h0;
reg [3:0] A_PIXEL3 = 4'h0;
reg [3:0] A_PIXEL4 = 4'h0;
reg [3:0] A_PIXEL5 = 4'h0;
reg [3:0] A_PIXEL6 = 4'h0;
reg [3:0] A_PIXEL7 = 4'h0;
reg [3:0] A_PIXEL_DELAY1;
reg [3:0] A_PIXEL_DELAY2;
reg [3:0] A_PIXEL_DELAY3;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
case(i_A_MODE)
2'b00: begin end
2'b01: begin //shift reversed direction(right)
A_PIXEL0 <= 4'h0;
A_PIXEL1 <= A_PIXEL0;
A_PIXEL2 <= A_PIXEL1;
A_PIXEL3 <= A_PIXEL2;
A_PIXEL4 <= A_PIXEL3;
A_PIXEL5 <= A_PIXEL4;
A_PIXEL6 <= A_PIXEL5;
A_PIXEL7 <= A_PIXEL6;
end
2'b10: begin
A_PIXEL0 <= A_PIXEL1;
A_PIXEL1 <= A_PIXEL2;
A_PIXEL2 <= A_PIXEL3;
A_PIXEL3 <= A_PIXEL4;
A_PIXEL4 <= A_PIXEL5;
A_PIXEL5 <= A_PIXEL6;
A_PIXEL6 <= A_PIXEL7;
A_PIXEL7 <= 4'h0;
end
2'b11: begin
A_PIXEL0 <= A_TILELINELATCH[31:28];
A_PIXEL1 <= A_TILELINELATCH[27:24];
A_PIXEL2 <= A_TILELINELATCH[23:20];
A_PIXEL3 <= A_TILELINELATCH[19:16];
A_PIXEL4 <= A_TILELINELATCH[15:12];
A_PIXEL5 <= A_TILELINELATCH[11:8];
A_PIXEL6 <= A_TILELINELATCH[7:4];
A_PIXEL7 <= A_TILELINELATCH[3:0];
end
endcase
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_AFF == 1'b0) begin
A_PIXEL_DELAY1 <= A_PIXEL0; //shift normally
end
else begin
A_PIXEL_DELAY1 <= A_PIXEL7; //shift reversed direction(right)
end
A_PIXEL_DELAY2 <= A_PIXEL_DELAY1;
A_PIXEL_DELAY3 <= A_PIXEL_DELAY2;
o_A_PIXEL <= A_PIXEL_DELAY3;
end
end
assign o_A_TRN_n = |{o_A_PIXEL};
//
// TM-B shift register
//
reg [3:0] B_PIXEL0 = 4'h0;
reg [3:0] B_PIXEL1 = 4'h0;
reg [3:0] B_PIXEL2 = 4'h0;
reg [3:0] B_PIXEL3 = 4'h0;
reg [3:0] B_PIXEL4 = 4'h0;
reg [3:0] B_PIXEL5 = 4'h0;
reg [3:0] B_PIXEL6 = 4'h0;
reg [3:0] B_PIXEL7 = 4'h0;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
case(i_B_MODE)
2'b00: begin end
2'b01: begin
B_PIXEL0 <= 4'h0;
B_PIXEL1 <= B_PIXEL0;
B_PIXEL2 <= B_PIXEL1;
B_PIXEL3 <= B_PIXEL2;
B_PIXEL4 <= B_PIXEL3;
B_PIXEL5 <= B_PIXEL4;
B_PIXEL6 <= B_PIXEL5;
B_PIXEL7 <= B_PIXEL6;
end
2'b10: begin
B_PIXEL0 <= B_PIXEL1;
B_PIXEL1 <= B_PIXEL2;
B_PIXEL2 <= B_PIXEL3;
B_PIXEL3 <= B_PIXEL4;
B_PIXEL4 <= B_PIXEL5;
B_PIXEL5 <= B_PIXEL6;
B_PIXEL6 <= B_PIXEL7;
B_PIXEL7 <= 4'h0;
end
2'b11: begin
B_PIXEL0 <= B_TILELINELATCH[31:28];
B_PIXEL1 <= B_TILELINELATCH[27:24];
B_PIXEL2 <= B_TILELINELATCH[23:20];
B_PIXEL3 <= B_TILELINELATCH[19:16];
B_PIXEL4 <= B_TILELINELATCH[15:12];
B_PIXEL5 <= B_TILELINELATCH[11:8];
B_PIXEL6 <= B_TILELINELATCH[7:4];
B_PIXEL7 <= B_TILELINELATCH[3:0];
end
endcase
end
end
always @(*) begin
if(i_BFF == 1'b0) begin
o_B_PIXEL <= B_PIXEL0; //shift normally
end
else begin
o_B_PIXEL <= B_PIXEL7; //shift reversed direction(right)
end
end
assign o_B_TRN_n = |{o_B_PIXEL};
endmodule

150
rtl/GX400_video/K005291.v Normal file
View File

@@ -0,0 +1,150 @@
/*
tilemapgen TILEMAP GENERATOR
*/
module K005291 (
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
//CPU flip
input wire i_HFLIP,
input wire i_VFLIP,
//HV counters
input wire i_ABS_n256H,
input wire i_ABS_128HA,
input wire i_ABS_64H,
input wire i_ABS_32H,
input wire i_ABS_16H,
input wire i_ABS_8H,
input wire i_ABS_4H,
input wire i_ABS_2H,
input wire i_ABS_1H,
input wire i_ABS_128V,
input wire i_ABS_64V,
input wire i_ABS_32V,
input wire i_ABS_16V,
input wire i_ABS_8V,
input wire i_ABS_4V,
input wire i_ABS_2V,
input wire i_ABS_1V,
input wire i_VCLK,
//CPU address/GFX data bus
input wire [11:0] i_CPU_ADDR,
input wire [7:0] i_GFXDATA,
//to CHARRAM
output reg [2:0] o_TILELINEADDR,
//to VRAM1+2
output wire [11:0] o_VRAMADDR,
output wire o_SHIFTA1,
output wire o_SHIFTA2,
output wire o_SHIFTB
);
wire ABS_4H = i_ABS_4H;
wire ABS_2H = i_ABS_2H;
wire ABS_1H = i_ABS_1H;
wire FLIP_n256H = i_ABS_n256H ^ i_HFLIP;
wire FLIP_128HA = i_ABS_128HA ^ i_HFLIP;
wire FLIP_64H = i_ABS_64H ^ i_HFLIP;
wire FLIP_32H = i_ABS_32H ^ i_HFLIP;
wire FLIP_16H = i_ABS_16H ^ i_HFLIP;
wire FLIP_8H = i_ABS_8H ^ i_HFLIP;
wire FLIP_4H = i_ABS_4H ^ i_HFLIP;
wire FLIP_2H = i_ABS_2H ^ i_HFLIP;
wire FLIP_1H = i_ABS_1H ^ i_HFLIP;
wire FLIP_128V = i_ABS_128V ^ i_VFLIP;
wire FLIP_64V = i_ABS_64V ^ i_VFLIP;
wire FLIP_32V = i_ABS_32V ^ i_VFLIP;
wire FLIP_16V = i_ABS_16V ^ i_VFLIP;
wire FLIP_8V = i_ABS_8V ^ i_VFLIP;
wire FLIP_4V = i_ABS_4V ^ i_VFLIP;
wire FLIP_2V = i_ABS_2V ^ i_VFLIP;
wire FLIP_1V = i_ABS_1V ^ i_VFLIP;
///////////////////////////////////////////////////////////
////// TILEMAP SCROLL
////
//
// HSCROLL
//
reg [8:0] TMA_HSCROLL_VALUE = 9'h1F;
reg [8:0] TMB_HSCROLL_VALUE = 9'h1F;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_VCLK) begin
case({ABS_4H, ABS_2H, ABS_1H})
3'd1: begin TMA_HSCROLL_VALUE[7:0] <= i_GFXDATA; end //latch TM-A lower bits at px1
3'd3: begin TMA_HSCROLL_VALUE[8] <= i_GFXDATA[0]; end //latch TM-B high bit at px3
3'd5: begin TMB_HSCROLL_VALUE[7:0] <= i_GFXDATA; end //latch TM-A lower bits at px5
3'd7: begin TMB_HSCROLL_VALUE[8] <= i_GFXDATA[0]; end //latch TM-B high bit at px7
default: begin end
endcase
end
end
end
//vram address
wire [5:0] horizontal_tile_addr; //6 bit: 64 horizontal tiles(512 horizontal pixels)
assign horizontal_tile_addr = (ABS_4H == 1'b0) ?
TMA_HSCROLL_VALUE[8:3] + {FLIP_n256H, FLIP_128HA, FLIP_64H, FLIP_32H, FLIP_16H, FLIP_8H} :
TMB_HSCROLL_VALUE[8:3] + {FLIP_n256H, FLIP_128HA, FLIP_64H, FLIP_32H, FLIP_16H, FLIP_8H};
//shift
assign o_SHIFTA1 = (TMA_HSCROLL_VALUE[2:0] + {FLIP_4H, FLIP_2H, FLIP_1H} == 3'd7) ? 1'b0 : 1'b1;
assign o_SHIFTA2 = (TMA_HSCROLL_VALUE[2:0] + {FLIP_4H, FLIP_2H, FLIP_1H} == 3'd3) ? 1'b0 : 1'b1;
assign o_SHIFTB = (TMB_HSCROLL_VALUE[2:0] + {FLIP_4H, FLIP_2H, FLIP_1H} == 3'd3) ? 1'b0 : 1'b1;
//
// VSCROLL
//
reg [7:0] TMAB_VSCROLL_VALUE = 8'hF;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
case({ABS_4H, ABS_2H, ABS_1H})
3'd3: begin TMAB_VSCROLL_VALUE <= i_GFXDATA; //latch TM-B second at px3
o_TILELINEADDR <= TMAB_VSCROLL_VALUE[2:0] + {FLIP_4V, FLIP_2V, FLIP_1V}; end
3'd7: begin TMAB_VSCROLL_VALUE <= i_GFXDATA; //latch TM-A first at px7
o_TILELINEADDR <= TMAB_VSCROLL_VALUE[2:0] + {FLIP_4V, FLIP_2V, FLIP_1V}; end
default: begin end
endcase
end
end
//pixel 3: get TM-B vscroll value
//pixel 7: get TM-A vscroll value/update TM-B line address
//pixel 3: get TM-B vscroll value/update TM-A line address
//vram address
wire [7:0] vertical_tile_addr; //[7:3] 5 bit: 32 vertical tiles(512 horizontal pixels)
assign vertical_tile_addr = TMAB_VSCROLL_VALUE + {FLIP_128V, FLIP_64V, FLIP_32V, FLIP_16V, FLIP_8V, FLIP_4V, FLIP_2V, FLIP_1V};
///////////////////////////////////////////////////////////
////// VRAM TILE ADDRESS
////
assign o_VRAMADDR = (ABS_2H == 1'b0) ?
i_CPU_ADDR :
{ABS_4H, vertical_tile_addr[7:3], horizontal_tile_addr};
endmodule

301
rtl/GX400_video/K005292.v Normal file
View File

@@ -0,0 +1,301 @@
module K005292 (
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
input wire i_MRST_n,
input wire i_HFLIP,
input wire i_VFLIP,
input wire i_H288, //set horizontal pixel as 288
input wire i_INTER, //interlaced
output reg o_HBLANK_n,
output wire o_VBLANK_n,
output wire o_VBLANKH_n,
output wire [8:0] o_ABS_H,
output wire [7:0] o_ABS_V,
output wire [7:0] o_FLIP_H,
output wire [7:0] o_FLIP_V,
output reg o_VCLK,
output wire o_FRAMEPARITY,
output reg o_HSYNC_n,
output wire o_VSYNC_n,
output reg o_CSYNC_n,
input wire [4:0] i_TEST, //PIN24 23 22 21 20
output wire [8:0] o_DEBUG_HCNTR,
output wire [8:0] o_DEBUG_VCNTR
);
///////////////////////////////////////////////////////////
////// CLOCK AND RESET
////
wire mrst = ~i_MRST_n;
wire mclk = i_EMU_MCLK;
wire clk6m_pcen = ~i_EMU_CLK6MPCEN_n;
///////////////////////////////////////////////////////////
////// GLOBAL SIGNALS
////
reg [8:0] hcntr, vcntr;
reg vclk_pcen;
assign o_ABS_H = hcntr;
assign o_FLIP_H = i_HFLIP ? ~hcntr[7:0] : hcntr[7:0];
assign o_ABS_V = vcntr[7:0];
assign o_FLIP_V = i_VFLIP ? ~vcntr[7:0] : vcntr[7:0];
assign o_DEBUG_HCNTR = hcntr;
assign o_DEBUG_VCNTR = vcntr;
///////////////////////////////////////////////////////////
////// HORIZONTAL COUNTER
////
always @(posedge mclk) begin
if(mrst) hcntr <= 9'd0;
else begin if(clk6m_pcen) begin
hcntr <= hcntr == 9'd511 ? 9'd128 : hcntr + 9'd1;
end end
end
///////////////////////////////////////////////////////////
////// VIDEO TIMINGS
////
//VERTICAL VIDEO TIMINGS
reg dff_D8, dff_D19, dff_C28;
wire dff_D19_pcen = vclk_pcen & (vcntr[4:0] == 5'd15) & ~(vcntr[7:5] == 3'b111) & (dff_D19 == 1'b0);
wire dff_C28_pcen = vclk_pcen & (vcntr[4:0] == 5'd15) & (dff_D19 == 1'b0 && vcntr[7:5] != 3'b111) & (dff_C28 == 1'b0);
always @(posedge mclk) begin
//D8
if(mrst) dff_D8 <= 1'b0;
else begin if(vclk_pcen) begin
if(vcntr[0] == 1'b0) dff_D8 <= ~vcntr[8];
end end
//D19
if(mrst) dff_D19 <= 1'b0;
else begin if(vclk_pcen) begin
if(vcntr[4:0] == 5'd15) dff_D19 <= ~(vcntr[7:5] == 3'b111);
end end
if(mrst) dff_C28 <= 1'b0;
else begin if(vclk_pcen) begin
if(vcntr[4:0] == 5'd15) if(dff_D19 == 1'b1 && vcntr[7:5] == 3'b111) dff_C28 <= ~dff_C28;
end end
end
assign o_VBLANK_n = dff_D19;
assign o_VSYNC_n = vcntr[8];
assign o_VBLANKH_n = (~vcntr[8] & ~dff_D8) | dff_D19;
assign o_FRAMEPARITY = dff_C28; //256V
//MODE0 VCLK/SYNC
reg vclk_mode0;
wire vclk_mode0_pcen = (hcntr[8] == 1'b0 && hcntr[6:0] == 7'd47) & clk6m_pcen;
always @(posedge mclk) begin
if(mrst) begin
vclk_mode0 <= 1'b1;
end
else begin if(clk6m_pcen) begin
if(hcntr == 9'd255 || hcntr[8]) vclk_mode0 <= 1'b0;
else begin
if(hcntr[3:0] == 4'd15) begin
vclk_mode0 <= ~hcntr[6] & hcntr[5];
end
end
end end
end
wire sync_mode0_n = ~vclk_mode0 & (vcntr[8] | ~i_TEST[4]);
//MODE2/3 VCLK/SYNC
reg vclk_mode23;
wire vclk_mode23_pcen = (hcntr[4:0] == 5'd31 && vclk_mode0) & clk6m_pcen;
always @(posedge mclk) begin
if(mrst) begin
vclk_mode23 <= 1'b0;
end
else begin if(clk6m_pcen) begin
if(hcntr[4:0] == 5'd31) vclk_mode23 <= vclk_mode0;
end end
end
reg dff_D41;
wire hblank_mode23_n = dff_D41 | hcntr[8];
always @(posedge mclk) begin
if(mrst) begin
dff_D41 <= 1'b0;
end
else begin if(clk6m_pcen) begin
if(hcntr[5:0] == 6'd31) dff_D41 <= hcntr[8];
end end
end
wire sync_mode23_n = ~vclk_mode23 & (vcntr[8] | ~i_TEST[4]);
//MODE1 VCLK/SYNC
reg dff_C2, dff_A44, dff_B43, dff_C14, dff_C8, dff_C8_censel;
wire dff_B43_ncen = (hcntr[5:0] == 6'd47 && (hcntr[8:6] == 3'b101 || hcntr[8:6] == 3'b010)) & clk6m_pcen;
wire debug_dff_C8_clk = ~dff_C14 && vcntr[7:0] == 8'b11110111 && i_TEST[4] && vclk_mode0;
wire debug_dff_C8_clk_pcen = ~dff_C14 && vcntr[7:0] == 8'b11110111 && i_TEST[4] && vclk_mode0_pcen;
wire debug_something_long = (hcntr[8:6] == 3'b101 || hcntr[8:6] == 3'b010);
always @(posedge mclk) begin
//B43
if(clk6m_pcen) begin
if(hcntr[5:0] == 6'd63 || ~hcntr[5]) dff_B43 <= 1'b1;
else begin
if(hcntr[4:0] == 5'd15) dff_B43 <= ~(hcntr[8:6] == 3'b101 || hcntr[8:6] == 3'b010);
end
end
//C14
if(mrst) dff_C14 <= 1'b1;
else begin
if(clk6m_pcen) begin
if(dff_D19_pcen || dff_D19) dff_C14 <= 1'b0;
else begin if(vclk_pcen) begin
if(vcntr[3:0] == 4'd7) dff_C14 <= ~dff_C14;
end end
end
end
//C8
if(mrst) dff_C8 <= 1'b0;
else begin
if(clk6m_pcen) begin
if(dff_C28_pcen || dff_C28) dff_C8 <= 1'b1;
else begin
if(vcntr[7:0] == 8'd247 && !dff_C14 && i_TEST[4] && vclk_mode0_pcen) dff_C8 <= ~dff_C8;
end
end
end
//C8_pre: NOT an original signal
if(mrst) dff_C8_censel <= 1'b0;
else begin if(clk6m_pcen) begin
if(hcntr == 9'd511 && vcntr == 9'd502) dff_C8_censel <= 1'b0;
else if(hcntr == 9'd511 && vcntr == 9'd271) dff_C8_censel <= 1'b1;
end end
//C2
if(mrst) dff_C2 <= 1'b0;
else begin
if(clk6m_pcen) begin
if(dff_D19_pcen || dff_D19) dff_C2 <= 1'b1;
else begin if(vclk_pcen) begin
if(vcntr[2:0] == 3'd7) dff_C2 <= ~dff_C2;
end end
end
end
//A44
if(clk6m_pcen) begin
if(!((hcntr == 9'd191 || hcntr[8:6] == 3'b010 || hcntr == 9'd383 || hcntr[8:6] == 3'b101) && !i_TEST[2])) dff_A44 <= 1'b0;
else begin
if(hcntr[4:0] == 5'd15) dff_A44 <= ~dff_A44;
end
end
end
reg vclk_mode1, vclk_mode1_pcen;
always @(*) begin
case(i_TEST[3:2])
2'b00: vclk_mode1 = dff_C8 ? vclk_mode0 : (~dff_B43 & hcntr[8]);
2'b01: vclk_mode1 = (~dff_B43 & hcntr[8]);
2'b10: vclk_mode1 = (vclk_mode0 & dff_C8);
2'b11: vclk_mode1 = 1'b0;
endcase
case(i_TEST[3:2])
2'b00: vclk_mode1_pcen = dff_C8_censel ? vclk_mode0_pcen : (dff_B43_ncen & hcntr[8]);
2'b01: vclk_mode1_pcen = (dff_B43_ncen & hcntr[8]);
2'b10: vclk_mode1_pcen = (vclk_mode0_pcen & dff_C8_censel);
2'b11: vclk_mode1_pcen = 1'b0;
endcase
end
wire gate_A12 = (~i_TEST[0] & dff_C2) | (i_TEST[3] | dff_B43) | (~i_TEST[0] & ~dff_C14);
wire gate_A29 = dff_A44 | (vcntr[8] | ~i_TEST[4]);
wire gate_B21 = dff_C14 | (~vclk_mode0 | i_TEST[3]);
wire sync_mode1_n = gate_A12 & gate_A29 & gate_B21;
///////////////////////////////////////////////////////////
////// TIMING MUX
////
always @(*) begin
case({i_H288, i_INTER})
2'b00: o_VCLK = vclk_mode0;
2'b01: o_VCLK = vclk_mode1;
2'b10: o_VCLK = vclk_mode23;
2'b11: o_VCLK = vclk_mode23;
endcase
case({i_H288, i_INTER})
2'b00: vclk_pcen = vclk_mode0_pcen;
2'b01: vclk_pcen = vclk_mode1_pcen;
2'b10: vclk_pcen = vclk_mode23_pcen;
2'b11: vclk_pcen = vclk_mode23_pcen;
endcase
o_HBLANK_n = i_H288 ? hblank_mode23_n : hcntr[8];
case({i_H288, i_INTER})
2'b00: o_CSYNC_n = sync_mode0_n;
2'b01: o_CSYNC_n = sync_mode1_n;
2'b10: o_CSYNC_n = sync_mode23_n;
2'b11: o_CSYNC_n = sync_mode23_n;
endcase
//for emulation
case({i_H288, i_INTER})
2'b00: o_HSYNC_n = ~vclk_mode0;
2'b01: o_HSYNC_n = gate_B21 & gate_A12 & ~(dff_A44 & ~vcntr[8]);
2'b10: o_HSYNC_n = ~vclk_mode23;
2'b11: o_HSYNC_n = ~vclk_mode23;
endcase
end
///////////////////////////////////////////////////////////
////// VERTICAL COUNTER
////
//async
//always @(posedge (vclk & i_TEST[1]) or posedge mrst) begin
// if(mrst) vcntr <= 9'd0;
// else begin
// vcntr <= vcntr == 9'd511 ? 9'd248 : vcntr + 9'd1;
// end
//end
//sync
always @(posedge mclk) begin
if(mrst) vcntr <= 9'd0;
else begin if(vclk_pcen) begin
vcntr <= vcntr == 9'd511 ? 9'd248 : vcntr + 9'd1;
end end
end
endmodule

545
rtl/GX400_video/K005293.v Normal file
View File

@@ -0,0 +1,545 @@
/*
prihandler PRIORITY HANDLER
*/
module K005293 (
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
//flip
input wire i_HFLIP,
//clocked shift
input wire i_SHIFTA1,
input wire i_SHIFTA2,
input wire i_SHIFTB,
//timings
input wire i_ABS_n1H,
input wire i_ABS_n6n7H,
input wire i_ABS_n2n3H,
//pixel input
input wire [3:0] i_A_PIXEL,
input wire [3:0] i_B_PIXEL,
//sprite pixels
input wire [15:0] i_OBJBUF_DATA,
//pixel transparent flag
input wire i_A_TRN_n,
input wire i_B_TRN_n,
//tile properties
input wire i_VHFF,
input wire [6:0] i_VC,
input wire [3:0] i_PR,
//delayed flips
output wire o_A_FLIP,
output wire o_B_FLIP,
//palette code
output reg [10:0] o_CD
);
///////////////////////////////////////////////////////////
////// PROPERTY DATA SHIFTER
////
/*
if SCROLL = 0
i_ABS_n2n3H i_ABS_n6n7H i_ABS_n2n3H i_ABS_n6n7H
i_SHIFTA1 i_SHIFTA2
i_SHIFTB
TM-A DELAY1 -> DELAY2 -> DELAY3 -> DELAY4
TM-B DELAY1 -> DELAY2 -> DELAY3
*/
//
// TM-A
//
//PR4, PR3, PR2, PR1, VHFF, VC6 ... VC0
reg [11:0] A_PROPERTY_DELAY1;
reg [11:0] A_PROPERTY_DELAY2;
reg [11:0] A_PROPERTY_DELAY3;
reg [11:0] A_PROPERTY_DELAY4;
wire [3:0] a_pr = A_PROPERTY_DELAY4[11:8];
wire [6:0] a_palette = A_PROPERTY_DELAY4[6:0];
assign o_A_FLIP = A_PROPERTY_DELAY3[7];
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n)begin
if((i_ABS_n2n3H || i_ABS_n1H) == 1'b0) A_PROPERTY_DELAY1 <= {i_PR, i_VHFF, i_VC}; //posedge of pixel 3
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if((i_ABS_n6n7H || i_ABS_n1H) == 1'b0) A_PROPERTY_DELAY2 <= A_PROPERTY_DELAY1; //posedge of pixel 7
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_SHIFTA1 == 1'b0) A_PROPERTY_DELAY3 <= A_PROPERTY_DELAY2; //posedge of SHIFT-A1
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_SHIFTA2 == 1'b0) A_PROPERTY_DELAY4 <= A_PROPERTY_DELAY3; //posedge of SHIFT-A2
end
end
//
// TM-B
//
reg [9:0] B_PROPERTY_DELAY1;
reg [9:0] B_PROPERTY_DELAY2;
reg [9:0] B_PROPERTY_DELAY3;
wire [1:0] b_pr = B_PROPERTY_DELAY3[9:8];
wire [6:0] b_palette = B_PROPERTY_DELAY3[6:0];
assign o_B_FLIP = B_PROPERTY_DELAY3[7];
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if((i_ABS_n6n7H || i_ABS_n1H) == 1'b0) B_PROPERTY_DELAY1 <= {i_PR[1:0], i_VHFF, i_VC}; //posedge of pixel 7
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if((i_ABS_n2n3H || i_ABS_n1H) == 1'b0) B_PROPERTY_DELAY2 <= B_PROPERTY_DELAY1; //posedge of pixel 3
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_SHIFTB == 1'b0) B_PROPERTY_DELAY3 <= B_PROPERTY_DELAY2; //posedge of SHIFT-B
end
end
///////////////////////////////////////////////////////////
////// SPRITE PIXEL LATCH
////
reg [7:0] OBJ_PIXEL0;
reg [7:0] OBJ_PIXEL1;
wire [7:0] obj_pixel;
wire obj_trn_n = (obj_pixel[3] | obj_pixel[2] | obj_pixel[1] | obj_pixel[0]);
assign obj_pixel = ((~i_ABS_n1H ^ i_HFLIP) == 1'b0) ? OBJ_PIXEL0 : OBJ_PIXEL1;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(i_ABS_n1H == 1'b0) begin//every odd pixel
OBJ_PIXEL1 <= i_OBJBUF_DATA[15:8]; //BUFFER A = ODD PIXEL
OBJ_PIXEL0 <= i_OBJBUF_DATA[7:0]; //BUFFER B = EVEN PIXEL
end
end
end
///////////////////////////////////////////////////////////
////// PRIORITY HANDLER
////
/*
K005293 priority handler. This chip was reverse-engineered
by Gilles Raimond, Olivier Scherler and me.
Since the exact behavior of the chip was not well known, I made a
brute-force program to test all PR inputs. The tool was programmed with
the advice of Raimond and Scherler, and was executed on my Bubble System.
The source of the program can be found on my GitHub page below:
github.com/ika-musume/BubbleDrive8/tree/master/BubbleDrive8_testprogram
The chip showed us a total of 26 results and suggested that the source
of MAME was a very empirical result.
*/
//determines which layer should be displayed first
reg [4:0] priority_mode; //set priority mode
reg [1:0] layer;
wire [2:0] transparency = ~{i_A_TRN_n, i_B_TRN_n, obj_trn_n};
//declare layer type
localparam TMA = 2'b00;
localparam TMB = 2'b01;
localparam OBJ = 2'b10;
//declare cases
`define PRCASE_A 5'd0 // A
`define PRCASE_A_B 5'd1 // A over B
`define PRCASE_A_B_O 5'd2 // A over B over Object
`define PRCASE_A_BMO 5'd3 // A over (B-masked Object)
`define PRCASE_A_O1 5'd4 // A over Object 1
`define PRCASE_A_O2 5'd5 // A over Object 2
`define PRCASE_A_O_B 5'd6 // A over Object over B
`define PRCASE_B 5'd7 // B
`define PRCASE_B_A 5'd8 // B over A
`define PRCASE_B_A_O 5'd9 // B over A over Object
`define PRCASE_B_O 5'd10 // B over Object
`define PRCASE_B_O_A 5'd11 // B over Object over A
`define PRCASE_O 5'd12 // Object
`define PRCASE_O_A 5'd13 // Object over A
`define PRCASE_O_A_B 5'd14 // Object over A over B
`define PRCASE_O_B 5'd15 // Object over B
`define PRCASE_O_B_A 5'd16 // Object over B over A
`define PRCASE_A_BMO_B 5'd17 // A over (B-masked Object) over B
`define PRCASE_APB_O 5'd18 // (A-punched B) over Object
`define PRCASE_APB_O_A 5'd19 // (A-punched B) over Object over A
`define PRCASE_B_AMO 5'd20 // B over (A-masked Object)
`define PRCASE_B_AMO_A 5'd21 // B over (A-masked Object) over A
`define PRCASE_BPA_O 5'd22 // (B-punched A) over Object
`define PRCASE_BPA_O_B 5'd23 // (B-punched A) over Object over B
`define PRCASE_O_APB 5'd24 // Object over (A-punched B)
`define PRCASE_O_BPA 5'd25 // Object over (B-punched A)
//X-decoder
always @(*) begin
casez({b_pr, a_pr}) //PR2, PR1, PR4, PR3, PR2, PR1
//|--TMB--| |------TMA-------|
6'b??_0101: priority_mode <= `PRCASE_A; // A
6'b?1_1101: priority_mode <= `PRCASE_A_B; // A over B
6'b?1_1111: priority_mode <= `PRCASE_A_B_O; // A over B over Object
6'b00_1101: priority_mode <= `PRCASE_A_BMO; // A over (B-masked Object)
6'b??_0111: priority_mode <= `PRCASE_A_O1; // A over Object 1
6'b00_1111: priority_mode <= `PRCASE_A_O2; // A over Object 2
6'b10_1111: priority_mode <= `PRCASE_A_O_B; // A over Object over B
6'b01_00??: priority_mode <= `PRCASE_B; // B
6'b01_10?1: priority_mode <= `PRCASE_B_A; // B over A
6'b11_10?1: priority_mode <= `PRCASE_B_A_O; // B over A over Object
6'b11_00??: priority_mode <= `PRCASE_B_O; // B over Object
6'b11_1000: priority_mode <= `PRCASE_B_O; // |
6'b11_1010: priority_mode <= `PRCASE_B_O_A; // B over Object over A
6'b00_00??: priority_mode <= `PRCASE_O; // Object
6'b00_1?00: priority_mode <= `PRCASE_O; // |
6'b??_0100: priority_mode <= `PRCASE_O; // |
6'b??_0110: priority_mode <= `PRCASE_O_A; // Object over A
6'b00_1110: priority_mode <= `PRCASE_O_A; // |
6'b10_1110: priority_mode <= `PRCASE_O_A_B; // Object over A over B
6'b10_00??: priority_mode <= `PRCASE_O_B; // Object over B
6'b10_1000: priority_mode <= `PRCASE_O_B; // |
6'b10_1010: priority_mode <= `PRCASE_O_B_A; // Object over B over A
6'b10_1101: priority_mode <= `PRCASE_A_BMO_B; // A over (B-masked Object) over B
6'b?1_1100: priority_mode <= `PRCASE_APB_O; // (A-punched B) over Object
6'b?1_1110: priority_mode <= `PRCASE_APB_O_A; // (A-punched B) over Object over A
6'b01_1000: priority_mode <= `PRCASE_B_AMO; // B over (A-masked Object)
6'b01_1010: priority_mode <= `PRCASE_B_AMO_A; // B over (A-masked Object) over A
6'b00_10?1: priority_mode <= `PRCASE_BPA_O; // (B-punched A) over Object
6'b10_10?1: priority_mode <= `PRCASE_BPA_O_B; // (B-punched A) over Object over B
6'b10_1100: priority_mode <= `PRCASE_O_APB; // Object over (A-punched B)
6'b00_1010: priority_mode <= `PRCASE_O_BPA; // Object over (B-punched A)
endcase
end
//Y and Z-decoder
always @(*) begin
case(priority_mode)
`PRCASE_A: begin
case(transparency)
3'b110: layer <= TMA; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= TMA; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMA;
endcase
end
`PRCASE_A_B: begin
case(transparency)
3'b110: layer <= TMA; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= TMB; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_A_B_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= TMB; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_A_BMO: begin
case(transparency)
3'b110: layer <= TMA; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= OBJ; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= OBJ;
endcase
end
`PRCASE_A_O1: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= OBJ; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMA;
endcase
end
`PRCASE_A_O2: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= OBJ; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= OBJ;
endcase
end
`PRCASE_A_O_B: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= OBJ; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B: begin
case(transparency)
3'b110: layer <= TMB; 3'b010: layer <= TMB; 3'b011: layer <= TMB; 3'b111: layer <= TMB;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_A: begin
case(transparency)
3'b110: layer <= TMB; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMB;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_A_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= OBJ;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_O_A: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= OBJ; 3'b101: layer <= OBJ;
endcase
end
`PRCASE_O_A: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= TMA; 3'b101: layer <= OBJ;
endcase
end
`PRCASE_O_A_B: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_O_B: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_O_B_A: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_A_BMO_B: begin
case(transparency)
3'b110: layer <= TMA; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= OBJ; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_APB_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= OBJ;
3'b100: layer <= TMB; 3'b000: layer <= OBJ; 3'b001: layer <= OBJ; 3'b101: layer <= TMB;
endcase
end
`PRCASE_APB_O_A: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= TMB; 3'b000: layer <= OBJ; 3'b001: layer <= TMA; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_AMO: begin
case(transparency)
3'b110: layer <= TMB; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= TMB;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_B_AMO_A: begin
case(transparency)
3'b110: layer <= TMB; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= TMB;
3'b100: layer <= TMB; 3'b000: layer <= TMB; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_BPA_O: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= OBJ; 3'b101: layer <= OBJ;
endcase
end
`PRCASE_BPA_O_B: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= TMB; 3'b101: layer <= TMB;
endcase
end
`PRCASE_O_APB: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= OBJ; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= OBJ; 3'b101: layer <= TMB;
endcase
end
`PRCASE_O_BPA: begin
case(transparency)
3'b110: layer <= OBJ; 3'b010: layer <= OBJ; 3'b011: layer <= TMA; 3'b111: layer <= OBJ;
3'b100: layer <= OBJ; 3'b000: layer <= OBJ; 3'b001: layer <= OBJ; 3'b101: layer <= OBJ;
endcase
end
default: begin
case(transparency)
3'b110: layer <= TMA; 3'b010: layer <= TMA; 3'b011: layer <= TMA; 3'b111: layer <= TMA;
3'b100: layer <= TMA; 3'b000: layer <= TMA; 3'b001: layer <= TMA; 3'b101: layer <= TMA;
endcase
end
endcase
end
//output latch
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if (layer == TMA) o_CD <= {a_palette, i_A_PIXEL};
else if(layer == TMB) o_CD <= {b_palette, i_B_PIXEL};
else o_CD <= {3'b000, obj_pixel};
end
end
endmodule

167
rtl/GX400_video/K005294.v Normal file
View File

@@ -0,0 +1,167 @@
/*
objlinelatch "LINELATCH"
*/
module K005294 (
input wire i_EMU_MCLK,
input wire i_EMU_CLK6MPCEN_n,
input wire [31:0] i_GFXDATA,
input wire [3:0] i_OC,
input wire i_TILELINELATCH_n,
output reg [7:0] o_DA,
output reg [7:0] o_DB,
//control signals
input wire i_WRTIME2,
input wire i_COLORLATCH_n,
input wire i_XPOS_D0,
input wire i_PIXELLATCH_WAIT_n,
input wire i_LATCH_A_D2,
input wire [2:0] i_PIXELSEL
);
///////////////////////////////////////////////////////////
////// COLORLATCH
////
//latches pixel palette data from VRAM
reg [3:0] OBJ_PALETTE;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(!i_COLORLATCH_n) OBJ_PALETTE <= i_OC;
end
end
///////////////////////////////////////////////////////////
////// TILELINE LATCH
////
reg [31:0] OBJ_TILELINELATCH;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(!i_TILELINELATCH_n) OBJ_TILELINELATCH <= i_GFXDATA; //posedge of px7
end
end
///////////////////////////////////////////////////////////
////// PIXEL SELECT / PIXELLATCH_WAIT / WRTIME2 DELAY
////
reg [2:0] pixelsel_dly [3:0];
reg [1:0] wrtime2_dly;
reg [3:0] pixellatch_wait_dly;
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
pixelsel_dly[0] <= i_PIXELSEL;
pixelsel_dly[1] <= pixelsel_dly[0];
pixelsel_dly[2] <= pixelsel_dly[1];
pixelsel_dly[3] <= pixelsel_dly[2];
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
wrtime2_dly[0] <= i_WRTIME2;
wrtime2_dly[1] <= wrtime2_dly[0];
end
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
pixellatch_wait_dly[3:1] <= pixellatch_wait_dly[2:0];
pixellatch_wait_dly[0] <= ~i_PIXELLATCH_WAIT_n;
end
end
///////////////////////////////////////////////////////////
////// PIXEL SELECTOR AND PIXEL LATCH
////
wire pixellatch_n = wrtime2_dly[1] | pixellatch_wait_dly[2];
reg [3:0] OBJ_PIXEL_LATCHED;
reg [3:0] OBJ_PIXEL_UNLATCHED;
always @(*)
begin
case(pixelsel_dly[3])
3'b000: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[31:28]; //pixel 0(A)
3'b001: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[27:24]; //pixel 1(B)
3'b010: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[23:20];
3'b011: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[19:16];
3'b100: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[15:12];
3'b101: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[11:8];
3'b110: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[7:4];
3'b111: OBJ_PIXEL_UNLATCHED <= OBJ_TILELINELATCH[3:0];
endcase
end
always @(posedge i_EMU_MCLK) begin
if(!i_EMU_CLK6MPCEN_n) begin
if(!pixellatch_n) OBJ_PIXEL_LATCHED <= OBJ_PIXEL_UNLATCHED;
end
end
///////////////////////////////////////////////////////////
////// DOUT MUX
////
always @(*)
begin
case({pixellatch_wait_dly[2], i_XPOS_D0})
2'b00: begin
o_DA <= {OBJ_PALETTE, OBJ_PIXEL_LATCHED};
o_DB <= {OBJ_PALETTE, OBJ_PIXEL_UNLATCHED};
end
2'b01: begin
o_DA <= {OBJ_PALETTE, OBJ_PIXEL_UNLATCHED};
o_DB <= {OBJ_PALETTE, OBJ_PIXEL_LATCHED};
end
2'b10: begin
o_DA <= {OBJ_PALETTE, OBJ_PIXEL_LATCHED};
o_DB <= {4'b0000, 4'b0000};
end
2'b11: begin
o_DA <= {4'b0000, 4'b0000};
o_DB <= {OBJ_PALETTE, OBJ_PIXEL_LATCHED};
end
endcase
end
endmodule

1657
rtl/GX400_video/K005295.v Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
42 4D 36 A0 02 00 00 00 00 00 36 00 00 00 28 00 00 00 00 01 00 00 E0 00 00 00 01 00 18 00 00 00 00 00 00 A0 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF

View File

@@ -0,0 +1 @@
00 01 02 04 05 06 08 09 0B 0D 0F 12 14 16 19 1C 21 24 29 2E 33 39 40 49 50 5B 68 78 8E A8 CC FF

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
module K005297_abspgcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_ABSPGCNTR_CNT_STOP,
input wire i_ABSPGCNTR_CNT_START,
input wire i_ALD_nB_U,
output wire o_ABSPGCNTR_LSB
);
///////////////////////////////////////////////////////////
////// RELATIVE PAGE COUNTER
////
/*
gte(greater than or equal) flag(>= 1531 evaluation)
relative page 0-1530: +522
relative page 1531-2052: -1531(loop)
*/
//SR shift enable
wire abspgcntr_shift; //shift flag
SRNAND I24 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[12]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(abspgcntr_shift));
//const add enable
wire abspgcntr_add_en;
SRNOR I34 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S(i_ABSPGCNTR_CNT_STOP), .i_R(i_ABSPGCNTR_CNT_START), .o_Q(), .o_Q_n(abspgcntr_add_en));
reg [11:0] abspgcntr = 12'd0; //abs page counter
wire abspgcntr_const, abspgcntr_fa_sum, abspgcntr_fa_cout; //FA carry out
reg abspgcntr_fa_cflag = 1'b0; //FA carry storage
assign o_ABSPGCNTR_LSB = abspgcntr_fa_sum & i_ALD_nB_U;
//shift register
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(abspgcntr_shift == 1'b1) begin
abspgcntr[11] <= o_ABSPGCNTR_LSB;
abspgcntr[10:0] <= abspgcntr[11:1];
end
else begin
abspgcntr <= abspgcntr;
end
end
end
//constant generator: +522 or -1531
wire constP522 = ~&{i_ROT20_n[9], i_ROT20_n[3], i_ROT20_n[1]};
wire constN1531 = ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]};
reg gte1531_evalreg = 1'b0;
reg gte1531_flag = 1'b0;
assign abspgcntr_const = (gte1531_flag == 1'b0) ? constP522 : constN1531;
//+522 : -1531
//evaluator: greater than or equal to 1531
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
gte1531_evalreg <= ((abspgcntr_fa_sum & ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]}) |
((o_ABSPGCNTR_LSB | ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]}) & gte1531_evalreg)) &
i_ROT20_n[19];
gte1531_flag <= (i_ROT20_n[12] == 1'b0) ? gte1531_evalreg : gte1531_flag;
end
end
//adder
FA J30 (.i_A(abspgcntr_add_en & abspgcntr_const), .i_B(abspgcntr_fa_cflag), .i_CIN(abspgcntr[0]), .o_S(abspgcntr_fa_sum), .o_COUT(abspgcntr_fa_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
abspgcntr_fa_cflag <= abspgcntr_fa_cout & i_ROT20_n[19];
end
end
endmodule

View File

@@ -0,0 +1,37 @@
module K005297_accmodeflag
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//system flags
input wire i_SYS_RST_n,
input wire i_SYS_RUN_FLAG,
//control
input wire i_CMDREG_RST_n,
input wire i_BDI_EN_SET_n,
input wire i_SYNCED_FLAG_SET_n,
//mode flag output
output wire o_BMODE_n, //bootloader mode
output wire o_UMODE_n, //user mode
output wire o_ALD_nB_U, //addres latch data BOOTLOADER_n / USER
output wire o_UMODE_SET_n
);
assign o_UMODE_SET_n = i_CMDREG_RST_n | i_BDI_EN_SET_n;
SRNAND C21 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_UMODE_SET_n), .i_R_n(i_SYS_RST_n), .o_Q(o_BMODE_n), .o_Q_n());
SRNAND C54 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_UMODE_SET_n), .i_R_n(i_SYS_RUN_FLAG), .o_Q(), .o_Q_n(o_UMODE_n));
SRNAND C19 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_UMODE_SET_n & i_SYS_RUN_FLAG), .i_R_n(i_SYNCED_FLAG_SET_n), .o_Q(o_ALD_nB_U), .o_Q_n());
endmodule

View File

@@ -0,0 +1,69 @@
module K005297_bubctrlfe
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//system flags
input wire i_SYS_RST_n,
input wire i_SYS_RUN_FLAG_SET_n,
//control
input wire i_ABSPGCNTR_CNT_START,
input wire i_ABSPGCNTR_CNT_STOP,
input wire i_VALPG_ACC_FLAG,
input wire i_BMODE_n,
input wire i_REP_START,
input wire i_SWAP_START,
output wire o_BOOTEN_n,
output wire o_BSS_n,
output wire o_BSEN_n,
output wire o_REPEN_n,
output wire o_SWAPEN_n
);
//Bubble Shift Start
SRNAND T6 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(~(i_ABSPGCNTR_CNT_START & ~i_ROT20_n[17])), .i_R_n(i_SYS_RUN_FLAG_SET_n & i_SYS_RST_n), .o_Q(), .o_Q_n(o_BSS_n));
//Bubble Shift Enable
SRNAND H22 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(~i_ABSPGCNTR_CNT_STOP & i_SYS_RST_n), .i_R_n(~(i_ABSPGCNTR_CNT_START & ~i_ROT20_n[1])), .o_Q(o_BSEN_n), .o_Q_n());
//Replicator Enable
reg bootloop_rep_pulse = 1'b1;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(o_BOOTEN_n | o_BSEN_n == 1'b1) begin //H25 NAND demorgan
bootloop_rep_pulse <= 1'b1;
end
else begin
if(i_ROT20_n[1] == 1'b0) begin
bootloop_rep_pulse <= ~bootloop_rep_pulse;
end
else begin
bootloop_rep_pulse <= bootloop_rep_pulse;
end
end
end
end
wire replicator_on = ~((~bootloop_rep_pulse | i_REP_START) & ~i_ROT20_n[2]);
SRNAND K24 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SYS_RST_n & i_ROT20_n[16]), .i_R_n(replicator_on), .o_Q(o_REPEN_n), .o_Q_n());
//Swap Gate Enable
SRNAND T15 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SYS_RST_n & i_ROT20_n[17]), .i_R_n(~((i_VALPG_ACC_FLAG & i_SWAP_START) & ~i_ROT20_n[3])), .o_Q(o_SWAPEN_n), .o_Q_n());
//Bootloop Enabe;
SRNAND C27 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SYS_RST_n), .i_R_n(~(i_BMODE_n & ~i_ROT20_n[0])), .o_Q(), .o_Q_n(o_BOOTEN_n));
endmodule

View File

@@ -0,0 +1,81 @@
module K005297_bubrdfe
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//system reset
input wire i_SYS_RST_n,
//control
input wire i_4BEN_n,
input wire i_BDI_EN_SET_n,
input wire i_BDI_EN_RST_n,
input wire [3:0] i_BDIN_n,
//output
output wire o_BDI,
output wire o_BDI_EN
);
//input enable
SRNAND F32 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n((i_BDI_EN_SET_n & i_SYS_RST_n)), .i_R_n(i_BDI_EN_RST_n), .o_Q(o_BDI_EN), .o_Q_n());
//mux select counter
reg [1:0] mux_cntr = 2'd0;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[0] == 1'b0) begin
mux_cntr <= 2'd0;
end
else begin
if(~(i_ROT20_n[3] & i_ROT20_n[8] & ~(~(i_ROT20_n[13] & i_ROT20_n[18]) & ~i_4BEN_n)) == 1'b1) begin //3-8_13-18
if(mux_cntr == 2'd3) begin
mux_cntr <= 2'd0;
end
else begin
mux_cntr <= mux_cntr + 2'd1;
end
end
else begin
mux_cntr <= mux_cntr;
end
end
end
end
//bubble inlatch
reg [3:0] bubble_inlatch;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[18] == 1'b0) begin //d-latch latches SR data at ROT20_n[19]
bubble_inlatch <= i_BDIN_n;
end
end
end
//in mux
reg bubble_stream;
wire [1:0] mux_select = {(mux_cntr[1] & ~i_4BEN_n), mux_cntr[0]};
always @(*) begin
case(mux_select) //bit3->2->1->0
2'd0: bubble_stream <= bubble_inlatch[3];
2'd1: bubble_stream <= bubble_inlatch[2];
2'd2: bubble_stream <= bubble_inlatch[1];
2'd3: bubble_stream <= bubble_inlatch[0];
endcase
end
assign o_BDI = ~bubble_stream & o_BDI_EN;
endmodule

View File

@@ -0,0 +1,69 @@
module K005297_bubwrfe
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_TST, //TST5
input wire i_4BEN_n,
input wire i_MUXED_BDO,
input wire i_MUXED_BDO_EN,
input wire i_SUPBD_END_n,
output wire [3:0] o_BDOUT_n,
//test mode
input wire i_ABSPGCNTR_LSB,
input wire i_PGREG_SR_LSB,
input wire i_DLCNTR_LSB,
input wire i_CYCLECNTR_LSB
);
//output enable
wire bubble_output_en;
SRNAND K22 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SUPBD_END_n), .i_R_n(~(i_MUXED_BDO_EN & ~i_ROT20_n[17])), .o_Q(), .o_Q_n(bubble_output_en));
//bubble shift register
reg [3:0] bubble_sr;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(~(i_ROT20_n[3] & i_ROT20_n[8] & ~(~(i_ROT20_n[13] & i_ROT20_n[18]) & ~i_4BEN_n)) == 1'b1) begin //3-8_13-18
bubble_sr[0] <= i_MUXED_BDO;
bubble_sr[3:1] <= bubble_sr[2:0];
end
else begin
bubble_sr <= bubble_sr;
end
end
end
//bubble outlatch
reg [3:0] bubble_outlatch;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[0] == 1'b0) begin //d-latch latches SR data at ROT20_n[1]
if(i_4BEN_n == 1'b1) begin //2bit mode
bubble_outlatch <= {bubble_sr[3:2], 2'b00};
end
else begin //4bit mode
bubble_outlatch <= bubble_sr;
end
end
end
end
//output mux
assign o_BDOUT_n = (i_TST == 1'b1) ? ~(bubble_outlatch & {4{bubble_output_en}}) :
{i_CYCLECNTR_LSB, i_DLCNTR_LSB, i_PGREG_SR_LSB, i_ABSPGCNTR_LSB};
endmodule

View File

@@ -0,0 +1,53 @@
module K005297_busctrlfe
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [7:0] i_ROT8,
//control
input wire i_DMA_ACT,
input wire i_DMA_WR_ACT_n,
output wire o_DMA_R_nW,
//bus control
output wire o_UDS_n,
output wire o_LDS_n,
output wire o_AS_n,
output wire o_R_nW
);
//DMA RW mode indicator
assign o_DMA_R_nW = (i_DMA_WR_ACT_n == 1'b0) ? 1'b0 : 1'b1; //write : read
//DATA STROBE(UDS+LDS)
wire data_strobe_set_n = (i_DMA_WR_ACT_n == 1'b0) ? ~i_ROT8[4] : ~i_ROT8[2]; //write : read
wire data_strobe_reset_n = (i_DMA_WR_ACT_n == 1'b0) ? (~i_ROT8[6] & i_DMA_ACT) : (~i_ROT8[7] & i_DMA_ACT); //write : read
wire data_strobe_n;
assign o_UDS_n = data_strobe_n;
assign o_LDS_n = data_strobe_n;
SRNAND C43 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(data_strobe_set_n), .i_R_n(data_strobe_reset_n), .o_Q(), .o_Q_n(data_strobe_n));
//ADDRESS STROBE
wire addr_strobe_set_n = ~i_ROT8[2];
wire addr_strobe_reset_n = ~i_ROT8[7] & i_DMA_ACT;
SRNAND C68 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(addr_strobe_set_n), .i_R_n(addr_strobe_reset_n), .o_Q(), .o_Q_n(o_AS_n));
//R/W
wire bus_read_n = (~i_ROT8[7] & i_DMA_ACT) & ~(i_ROT8[2] & o_DMA_R_nW);
wire bus_write_n = ~i_ROT8[2] | ~(~o_DMA_R_nW & i_DMA_ACT);
SRNAND C53 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(bus_write_n), .i_R_n(bus_read_n), .o_Q(), .o_Q_n(o_R_nW));
endmodule

View File

@@ -0,0 +1,68 @@
module K005297_byteacqcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_4BEN_n,
input wire i_GLCNT_RD,
input wire i_NEWBYTE,
input wire i_ACC_ACT_n,
input wire i_BUBWR_WAIT,
output reg o_BYTEACQ_DONE = 1'b0
);
///////////////////////////////////////////////////////////
////// BYTE ACQUISITION COUNTER
////
//byte acquisition counter
reg [2:0] byte_acq_cntr = 3'h7;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if((i_NEWBYTE | i_ACC_ACT_n) == 1'b1) begin //reset
byte_acq_cntr <= 3'h7;
end
else begin
if(i_GLCNT_RD == 1'b1) begin
if(byte_acq_cntr == 3'h0) begin
byte_acq_cntr <= 3'h7;
end
else begin
byte_acq_cntr <= byte_acq_cntr - 3'h1;
end
end
else begin
byte_acq_cntr <= byte_acq_cntr;
end
end
end
end
//flag
wire eq7 = (byte_acq_cntr == 3'h0) ? 1'b1 : 1'b0;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(~(i_ROT20_n[3] & i_ROT20_n[8] & ~(~(i_ROT20_n[13] & i_ROT20_n[18]) & ~i_4BEN_n)) == 1'b1) begin //3-8_13-18
o_BYTEACQ_DONE <= eq7 | i_BUBWR_WAIT;
end
else begin
o_BYTEACQ_DONE <= o_BYTEACQ_DONE;
end
end
end
endmodule

View File

@@ -0,0 +1,63 @@
module K005297_cyclecntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_CYCLECNTR_EN,
output wire o_CYCLECNTR_LSB
);
///////////////////////////////////////////////////////////
////// CYCLE COUNTER
////
/*
+1 serial up counter
*/
//shift flag
wire cyclecntr_shift;
SRNAND Q67 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[10]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(cyclecntr_shift));
reg [9:0] cyclecntr = 10'd0; //cycle counter
wire cyclecntr_fa_sum; //msb input
wire cyclecntr_fa_cout; //FA carry out
reg cyclecntr_fa_cflag = 1'b0; //FA carry storage
assign o_CYCLECNTR_LSB = cyclecntr[0];
//serial full adder cell
FA K20 (.i_A(~i_ROT20_n[0]), .i_B(cyclecntr[0]), .i_CIN(cyclecntr_fa_cflag), .o_S(cyclecntr_fa_sum), .o_COUT(cyclecntr_fa_cout));
//previous carry bit storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
cyclecntr_fa_cflag <= cyclecntr_fa_cout & i_ROT20_n[19];
end
end
//shift register
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(cyclecntr_shift == 1'b1) begin
cyclecntr[9] <= cyclecntr_fa_sum & i_CYCLECNTR_EN;
cyclecntr[8:0] <= cyclecntr[9:1];
end
else begin
cyclecntr <= cyclecntr;
end
end
end
endmodule

View File

@@ -0,0 +1,72 @@
module K005297_dlcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_DLCNT_START_n, //data length count start
input wire i_SUPBD_START_n, //data length count end
input wire i_DLCNT_EN, //data length + 1
output wire o_DLCNTR_LSB, //data length counter lsb
output wire o_DLCNTR_CFLAG //carry of data length's msb
);
///////////////////////////////////////////////////////////
////// DATA LENGTH COUNTER
////
/*
+1 serial up counter
*/
//reset flag(load 0)
wire dlcntr_rst_n;
SRNAND I46 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SUPBD_START_n), .i_R_n(i_DLCNT_START_n), .o_Q(), .o_Q_n(dlcntr_rst_n));
//shift flag
wire dlcntr_shift;
SRNAND J67 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[10]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(dlcntr_shift));
reg [9:0] dlcntr = 10'd0; //data length counter
wire dlcntr_fa_sum; //msb input
wire dlcntr_fa_cout; //FA carry out
reg dlcntr_fa_cflag = 1'b0; //FA carry storage
assign o_DLCNTR_LSB = dlcntr[0];
assign o_DLCNTR_CFLAG = dlcntr_fa_cflag;
//serial full adder cell
FA I61 (.i_A(dlcntr[0]), .i_B(dlcntr_fa_cflag), .i_CIN(i_DLCNT_EN), .o_S(dlcntr_fa_sum), .o_COUT(dlcntr_fa_cout));
//previous carry bit storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
dlcntr_fa_cflag <= dlcntr_fa_cout & i_ROT20_n[19];
end
end
//shift register
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(dlcntr_shift == 1'b1) begin
dlcntr[9] <= dlcntr_fa_sum & dlcntr_rst_n;
dlcntr[8:0] <= dlcntr[9:1];
end
else begin
dlcntr <= dlcntr;
end
end
end
endmodule

View File

@@ -0,0 +1,80 @@
module K005297_dleval
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_TST,
input wire i_SYS_RST_n,
input wire i_4BEN_n,
input wire i_UMODE_n,
input wire i_DLCNTR_LSB,
input wire i_DLCNTR_CFLAG,
input wire i_BYTEACQ_DONE,
input wire i_SUPBD_END_n,
output wire o_SUPBD_START_n
);
///////////////////////////////////////////////////////////
////// DATA LENGTH COUNTER
////
//eq480
wire const480 = ~&{i_ROT20_n[8], i_ROT20_n[7], i_ROT20_n[6], i_ROT20_n[5]};
reg eq480_flag_n = 1'b0;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
eq480_flag_n <= (((i_DLCNTR_LSB ^ const480) | eq480_flag_n) & i_ROT20_n[19]);
end
end
//bootloader done flag
reg boot_done = 1'b0;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
boot_done <= (i_ROT20_n[9] == 1'b0) ? (~eq480_flag_n | i_TST) & i_UMODE_n :
boot_done & i_UMODE_n;
end
end
//page done flag
reg pg_done = 1'b0;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_4BEN_n == 1'b1) begin //2bit mode
pg_done <= (i_ROT20_n[7] == 1'b0) ? ((i_TST | i_DLCNTR_CFLAG) & ~i_UMODE_n) : pg_done;
end
else begin //4bit mode
pg_done <= (i_ROT20_n[8] == 1'b0) ? ((i_TST | i_DLCNTR_CFLAG) & ~i_UMODE_n) : pg_done;
end
end
end
///////////////////////////////////////////////////////////
////// EFFECTIVE BUBBLE DATA END FLAG
////
wire effbd_done = ~((boot_done | pg_done) & ~i_ROT20_n[10]);
wire supbd_rdy;
assign o_SUPBD_START_n = ~&{supbd_rdy, i_BYTEACQ_DONE, ~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n))} & i_SYS_RST_n;
SRNAND K23 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SUPBD_END_n), .i_R_n(effbd_done), .o_Q(), .o_Q_n(supbd_rdy));
endmodule

View File

@@ -0,0 +1,115 @@
module K005297_dmaaddrcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [7:0] i_ROT8,
//control
input wire i_ALD_nB_U,
input wire i_ADDR_RST,
input wire i_BDRWADDR_INC,
input wire i_MSKADDR_INC,
output wire [6:0] o_AOUT, //A7-A1
output wire [3:0] o_ALD_DMABD, //bubble data
output wire o_ALD_DMAMSK //error map
);
///////////////////////////////////////////////////////////
////// DMA TX(BUBBLE DATA) ADDRESS COUNTER
////
reg [10:0] dmabd_addr_cntr = 11'h000;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ADDR_RST == 1'b1) begin
dmabd_addr_cntr <= 11'h000;
end
else begin
if((i_BDRWADDR_INC & i_ROT8[1]) == 1'b1) begin //count up
if(i_ALD_nB_U == 1'b0) begin //bootloader
if(dmabd_addr_cntr == 11'h7FF) begin
dmabd_addr_cntr <= 11'h000;
end
else begin
dmabd_addr_cntr <= dmabd_addr_cntr + 11'h001;
end
end
else begin //user pages
if(dmabd_addr_cntr == 11'h0FF) begin
dmabd_addr_cntr <= 11'h000;
end
else begin
dmabd_addr_cntr <= dmabd_addr_cntr + 11'h001;
end
end
end
else begin
dmabd_addr_cntr <= dmabd_addr_cntr;
end
end
end
end
///////////////////////////////////////////////////////////
////// DMA RX(ERROR MAP) ADDRESS COUNTER
////
//mskaddr inc latch(why?)
reg mskaddr_inc_latched;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[1] == 1'b1) begin //D-latch latches this at ROT8[2] == 1'b1;
mskaddr_inc_latched <= i_MSKADDR_INC;
end
end
end
//address counter
reg [7:0] dmamsk_addr_cntr = 8'h00;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ADDR_RST == 1'b1) begin
dmamsk_addr_cntr <= 8'h00;
end
else begin
if((mskaddr_inc_latched & i_ROT8[1]) == 1'b1) begin //count up
if(dmamsk_addr_cntr == 8'hFF) begin
dmamsk_addr_cntr <= 8'h00;
end
else begin
dmamsk_addr_cntr <= dmamsk_addr_cntr + 8'h01;
end
end
else begin
dmamsk_addr_cntr <= dmamsk_addr_cntr;
end
end
end
end
///////////////////////////////////////////////////////////
////// OUTPUTS
////
assign o_AOUT = (i_MSKADDR_INC == 1'b0) ? dmabd_addr_cntr[6:0] : dmamsk_addr_cntr[6:0];
assign o_ALD_DMABD = dmabd_addr_cntr[10:7];
assign o_ALD_DMAMSK = dmamsk_addr_cntr[7];
endmodule

View File

@@ -0,0 +1,79 @@
module K005297_dmadreg
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [7:0] i_ROT8,
//control
input wire i_DMADREG_SHIFT,
input wire i_DMADREG_BDLD_EN,
input wire i_DMADREG_BDHI_LD,
input wire i_DMADREG_BDLO_LD,
input wire i_DMADREG_BDHILO_LD,
input wire i_DMA_ACT,
input wire i_BDI_EN,
input wire i_GLCNT_RD,
output wire o_BDRWADDR_INC,
input wire i_MUXED_BDI, //muxed bubble data input(bubble read)
output wire [15:0] o_DMATXREG, //parallel bubble read data(DMA TX)
output wire o_EFF_BDO, //effective bubble data output(bubble write)
input wire [15:0] i_DIN //parallel bubble write data(DMA RX)
);
///////////////////////////////////////////////////////////
////// DMA DATA REGISTER
////
//word load request(for write?)
reg txreg_word_ld_rq = 1'b0;
wire txreg_word_ld = txreg_word_ld_rq & i_DMA_ACT & i_ROT8[6];
assign o_BDRWADDR_INC = txreg_word_ld_rq;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[1] == 1'b1) begin
txreg_word_ld_rq <= i_DMADREG_BDHILO_LD; //latches at i_ROT8[2]; source latch launches at i_ROT8[7]
end
end
end
//8 bit shift register for data IO
reg [7:0] bytesr;
assign o_EFF_BDO = bytesr[7];
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
case({i_GLCNT_RD, i_DMADREG_SHIFT})
2'b00: bytesr <= bytesr; //hold
2'b01: bytesr <= bytesr;
2'b10: bytesr <= (i_DMADREG_BDHI_LD == 1'b0) ? o_DMATXREG[7:0] : o_DMATXREG[15:8]; //parallel load(bubble write)
2'b11: begin bytesr[0] <= i_MUXED_BDI; bytesr[7:1] <= bytesr[6:0]; end //serial load(bubble read)
endcase
end
end
//D latch * 16
wire txreg_hi_ld = (i_BDI_EN == 1'b1) ? (i_DMADREG_BDHI_LD & i_DMADREG_BDLD_EN) : txreg_word_ld;
wire txreg_lo_ld = (i_BDI_EN == 1'b1) ? (i_DMADREG_BDLO_LD & i_DMADREG_BDLD_EN) : txreg_word_ld;
wire [7:0] txreg_hi_data = (i_BDI_EN == 1'b1) ? bytesr: i_DIN[15:8];
wire [7:0] txreg_lo_data = (i_BDI_EN == 1'b1) ? bytesr: i_DIN[7:0];
DL #(.dw(8)) DMATXREGHI (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_EN(txreg_hi_ld), .i_D(txreg_hi_data), .o_Q(o_DMATXREG[15:8]), .o_Q_n());
DL #(.dw(8)) DMATXREGLO (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_EN(txreg_lo_ld), .i_D(txreg_lo_data), .o_Q(o_DMATXREG[7:0]), .o_Q_n());
endmodule

View File

@@ -0,0 +1,130 @@
module K005297_dmadregldctrl
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//control
input wire i_4BEN_n,
input wire i_BDI_EN,
input wire i_UMODE_n,
input wire i_ACQ_MSK_LD,
input wire i_MSKREG_SR_LD,
input wire i_BYTEACQ_DONE,
input wire i_GLCNT_RD,
input wire i_ACQ_START,
input wire i_SUPBD_START_n,
input wire i_VALPG_FLAG_SET_n,
input wire i_PGREG_SR_LSB,
input wire i_DLCNTR_LSB,
input wire i_DMA_WORD_END,
output wire o_NEWBYTE,
output wire o_DLCNT_EN,
output reg o_DMADREG_BDHI_LD = 1'b1,
output wire o_DMADREG_BDLO_LD
);
//NEWBYTE for DMA outlatch control
reg initial_newbyte; //only asserted at the beginning
assign o_NEWBYTE = initial_newbyte | i_BYTEACQ_DONE & i_GLCNT_RD;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
initial_newbyte <= i_ACQ_MSK_LD & (i_MSKREG_SR_LD & ~i_ROT20_n[1]) & i_BDI_EN;
end
end
//bootloader related
wire newbyte_dlyd;
assign o_DLCNT_EN = newbyte_dlyd & ~i_ROT20_n[0];
SRNAND K33 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[1]), .i_R_n(~o_NEWBYTE), .o_Q(), .o_Q_n(newbyte_dlyd));
//user page related
wire valpg_dma_req;
SRNAND J38 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SUPBD_START_n), .i_R_n(i_VALPG_FLAG_SET_n), .o_Q(), .o_Q_n(valpg_dma_req));
reg dlcntr_cmp, dlcntr_zero_n;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
dlcntr_cmp <= (((i_DLCNTR_LSB ^ (i_PGREG_SR_LSB | valpg_dma_req)) | dlcntr_cmp) & i_ROT20_n[19]) | i_UMODE_n;
dlcntr_zero_n <= (i_4BEN_n == 1'b1) ? ((i_ROT20_n[7] == 1'b0) ? dlcntr_cmp : dlcntr_zero_n) :
((i_ROT20_n[8] == 1'b0) ? dlcntr_cmp : dlcntr_zero_n); //2bit : 4bit
end
end
reg init_dma_req = 1'b0; //this sr latch's outer circuit has a combinational loop
//RESET PORT(flag set) ACQ_START @ D0
//SET PORT(flag reset) ACQ_MSK_LD @ D4(stable before D4)
always @(posedge i_MCLK) begin
if(i_SYS_RST_n == 1'b0) begin //synchronous reset(SR latch originally)
init_dma_req <= 1'b0;
end
else begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[19] == 1'b0) begin //SR latch's reset works @ ROT20[0]
if(i_ACQ_START == 1'b1) begin
init_dma_req <= 1'b1;
end
end
else if(i_ROT20_n[3] == 1'b0) begin
if(init_dma_req & ~i_ACQ_MSK_LD == 1'b1) begin
init_dma_req <= 1'b0;
end
end
else begin
init_dma_req <= init_dma_req;
end
end
end
end
//SR latch
wire bootloader_dma_req;
SRNAND K38 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(~(o_NEWBYTE & dlcntr_zero_n)), .i_R_n(~(o_DLCNT_EN & ~dlcntr_zero_n)), .o_Q(bootloader_dma_req), .o_Q_n());
//DMADREG HI/LO toggle
wire dmadreg_toggle_hilo = ~(init_dma_req & i_BDI_EN) & (~valpg_dma_req | bootloader_dma_req) & o_NEWBYTE;
//K50 TFF
assign o_DMADREG_BDLO_LD = ~o_DMADREG_BDHI_LD;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_DMA_WORD_END == 1'b1) begin //reset
o_DMADREG_BDHI_LD <= 1'b1;
end
else begin
if(dmadreg_toggle_hilo == 1'b1) begin
o_DMADREG_BDHI_LD <= ~o_DMADREG_BDHI_LD;
end
else begin
o_DMADREG_BDHI_LD <= o_DMADREG_BDHI_LD;
end
end
end
end
endmodule

View File

@@ -0,0 +1,97 @@
module K005297_dmafe
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [7:0] i_ROT8,
//reset
input wire i_SYS_RST_n,
//68000
input wire i_CPURST_n,
input wire i_AS_n,
input wire i_BG_n,
output wire o_BR_n,
output wire o_BGACK_n,
//control
input wire i_BR_START_n,
input wire i_DMA_END,
output wire o_ALD_EN,
output wire o_DMA_ACT
);
///////////////////////////////////////////////////////////
////// DMA FRONTEND
////
//
// USE 4MHz CLOCK
//
//DMA ACT flag
//This SR latch receives the SET signal from the asynchronous source during ROT8[7] = 1
//so, sample the SET signal twice, at both posedge and negedge of ROT8[7] = 1
reg dma_act_set_n;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[6] == 1'b1) begin //async signal from CPU, sample them here, latch C83 @ posedge ROT8[7]
dma_act_set_n <= ~(~o_BR_n & (i_AS_n | ~i_CPURST_n) & ~(i_BG_n & i_CPURST_n)); //C87 NAND
end
else if(i_ROT8[7] == 1'b1) begin //async signal from CPU, sample them here, latch C83 @ negedge ROT8[7]
dma_act_set_n <= ~(~o_BR_n & (i_AS_n | ~i_CPURST_n) & ~(i_BG_n & i_CPURST_n)); //C87 NAND
end
else begin //disable
dma_act_set_n <= 1'b1;
end
end
end
reg dma_act_reset_n;
reg dma_end_dlyd;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
dma_end_dlyd <= i_DMA_END;
dma_act_reset_n <= ~((i_DMA_END & ~dma_end_dlyd) | ~i_SYS_RST_n);
end
end
SRNAND C83 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(dma_act_set_n), .i_R_n(dma_act_reset_n), .o_Q(o_DMA_ACT), .o_Q_n());
//BGACK
SRNAND C86 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(dma_act_reset_n | o_DMA_ACT), .i_R_n(dma_act_set_n), .o_Q(o_BGACK_n), .o_Q_n()); //set port: demorgan
//BR
reg br_start_dlyd;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
br_start_dlyd <= ~i_BR_START_n;
end
end
wire br_set_n = i_BR_START_n | br_start_dlyd;
wire br_reset_n = ~((o_DMA_ACT & i_ROT8[1]) | ~i_SYS_RST_n);
SRNAND C88 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(br_reset_n), .i_R_n(br_set_n), .o_Q(o_BR_n), .o_Q_n()); //set port: demorgan
//Address Latch Enable
//Glitch can occur here. Not a serious one. Solve.
wire ald_en_set_n = ~(o_DMA_ACT & i_ROT8[0]);
wire ald_en_reset_n = ~((o_DMA_ACT & i_ROT8[2]) | ~i_SYS_RST_n);
SRNAND C70 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(ald_en_reset_n), .i_R_n(ald_en_set_n), .o_Q(), .o_Q_n(o_ALD_EN));
endmodule

View File

@@ -0,0 +1,148 @@
module K005297_dmatiming
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [7:0] i_ROT8,
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//system flags
input wire i_UMODE_n,
input wire i_ACC_ACT_n,
input wire i_DMA_ACT,
input wire i_BDI_EN,
input wire i_MSKREG_SR_LD,
input wire i_ACQ_MSK_LD,
input wire i_ACQ_START,
input wire i_SUPBDO_EN_n,
input wire i_DMADREG_BDLO_LD,
output reg o_BR_START_n,
output wire o_DMA_END,
output wire o_DMA_WORD_END,
output wire o_MSKREG_LD,
output wire o_MSKADDR_INC,
output wire o_DMADREG_BDHILO_LD,
output wire o_DMA_WR_ACT_n
);
///////////////////////////////////////////////////////////
////// DMA TIMINGS
////
//
// USE 4MHz CLOCK
//
//BDLO_LD negedge detection
reg dmareg_bdlo_ld_dlyd;
wire dmareg_bdlo_ld_negedge = dmareg_bdlo_ld_dlyd & ~i_DMADREG_BDLO_LD;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
dmareg_bdlo_ld_dlyd <= i_DMADREG_BDLO_LD;
end
end
//dma command d1 SRNOR control
wire dma_command_d1_set = o_MSKREG_LD | ~i_SYS_RST_n;
wire dma_command_d1_reset = ~(i_UMODE_n | ~((i_MSKREG_SR_LD & ~i_ROT20_n[1]) | (i_ACQ_MSK_LD & ~i_ROT20_n[3])));
//dma command d0 SRNAND control
wire dma_command_d0_set_n = ~(~(~(o_DMADREG_BDHILO_LD & i_ROT8[3]) & ~(i_ACQ_START & ~i_ROT20_n[0]) & i_SUPBDO_EN_n) | ~i_SYS_RST_n);
wire dma_command_d0_reset_n = ~(((i_ACQ_MSK_LD & ~i_ROT20_n[3]) & ~i_BDI_EN) | dmareg_bdlo_ld_negedge);
assign o_DMA_WORD_END = ~dma_command_d0_set_n;
//dma commands from sr latches
wire [1:0] dma_command_input; //[G5, F20]
//G5, d1
SRNOR G5 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S(dma_command_d1_set), .i_R(dma_command_d1_reset), .o_Q(), .o_Q_n(dma_command_input[1]));
//F50, d0
SRNAND F50 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(dma_command_d0_set_n), .i_R_n(dma_command_d0_reset_n), .o_Q(), .o_Q_n(dma_command_input[0]));
//dma command control block
//rot8 4 5 6 7 0 1 2 3 4 5 6 7
//rot20 0 1 2 3 4 5
//dma command input is stable at falling edge of ROT8[3], because the launching latches are all enabled by ROT8[3] or ROT20[3]
reg dma_command_lock_n = 1'b0; //latches command status at ROT8[3] == 1
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[3] == 1'b1) begin
if(dma_command_lock_n == 1'b0) begin
if(i_ACC_ACT_n == 1'b0) begin
dma_command_lock_n <= 1'b1; //unlock
end
else begin
dma_command_lock_n <= 1'b0; //lock hold
end
end
else begin
if(i_ACC_ACT_n & ~|{dma_command_input} == 1'b1) begin
dma_command_lock_n <= 1'b0; //lock
end
else begin
dma_command_lock_n <= 1'b1; //unlock
end
end
if(dma_command_lock_n == 1'b0) begin
if(i_ACC_ACT_n == 1'b0) begin //unlock
o_BR_START_n <= ~|{dma_command_input};
end
else begin
o_BR_START_n <= 1'b1; //still locked
end
end
else begin
if(i_ACC_ACT_n == 1'b0) begin //free
o_BR_START_n <= ~|{dma_command_input};
end
else begin
o_BR_START_n <= ~|{dma_command_input}; //locks when NOR(dmainput) is 1
end
end
end
end
end
reg [1:0] dma_command_0; //d-latch @ ROT8[4]
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[4] == 1'b1) begin
dma_command_0 <= dma_command_input & {2{(dma_command_lock_n & i_SYS_RST_n)}};
end
end
end
reg [1:0] dma_command_1; //d-latch @ ROT8[7]
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
if(i_ROT8[6] == 1'b1) begin
dma_command_1 <= dma_command_0 & {2{(dma_command_lock_n)}};
end
end
end
assign o_DMA_END = ~( dma_command_1[1] | dma_command_1[0]);
assign o_MSKADDR_INC = ( dma_command_1[1] & ~dma_command_1[0] & i_DMA_ACT);
assign o_MSKREG_LD = o_MSKADDR_INC & i_ROT8[3];
assign o_DMADREG_BDHILO_LD = ( dma_command_1[1] & dma_command_1[0] & i_DMA_ACT) |
(~dma_command_1[1] & dma_command_1[0] & i_DMA_ACT);
assign o_DMA_WR_ACT_n = o_MSKADDR_INC | ~o_DMADREG_BDHILO_LD | ~i_BDI_EN;
endmodule

View File

@@ -0,0 +1,355 @@
module K005297_fsm
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//CMDREG related
input wire i_CMDREG_RDREQ,
input wire i_CMDREG_WRREQ,
output wire o_CMDREG_RST_n,
//system flags
input wire i_SYS_RUN_FLAG,
input wire i_SYS_ERR_FLAG,
output wire o_FSMERR_RESTART_n,
input wire i_SUPBD_ACT_n,
input wire i_PGCMP_EQ,
input wire i_VALPG_ACC_FLAG,
input wire i_PGREG_SR_SHIFT,
input wire i_SUMEQ_n,
input wire i_MUXED_BDO_EN_DLYD,
input wire i_OP_DONE, //???
//bubble input enable
output wire o_BDI_EN_SET_n,
output wire o_BDI_EN_RST_n,
//page register shift register parallel load enable
output wire o_PGREG_SRLD_EN,
//bubble IO related
output wire o_ACC_START,
output wire o_REP_START,
//???
output wire o_CMD_ACCEPTED_n //???
);
/*
FSM STATE
0: Initial state
1: Bootloader Z14(CRC14 zero) flag check state. If nz, hangs on here.
2: User mode idle
3: R/W request acceptance
4: Wait for page swapping
5: Wait for page replication
6: Swap start
7: Page R/W operation
bootloader:
0->1->2
page read:
2->3->5->7->2
page write:
2->3->4->7->2
*/
///////////////////////////////////////////////////////////
////// FSM STATE REGISTER
////
reg [2:0] fsmstat_sr = 3'b000; //state register
wire fsmstat_shift; //shift flag: 4-5-6, Q38 SRNAND
SRNAND Q38 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[7]), .i_R_n(i_ROT20_n[4]), .o_Q(), .o_Q_n(fsmstat_shift));
//state adder variable
reg [1:0] fsmstat_nxtstat = 2'd3; //3: 1'b0, 2: nROT20[5], 1: nROT20[4], 0: nROT20[4, 5]
reg fsmstat_var;
always @(*) begin
case(fsmstat_nxtstat)
2'd0: fsmstat_var <= ~(i_ROT20_n[4] & i_ROT20_n[5]);
2'd1: fsmstat_var <= ~i_ROT20_n[4];
2'd2: fsmstat_var <= ~i_ROT20_n[5];
2'd3: fsmstat_var <= 1'b0;
endcase
end
//wire fsmstat_var = (fsmstat_nxtstat[1] == 1'b1) ? ((fsmstat_nxtstat[0] == 1'b1) ? 1'b0 : ~i_ROT20_n[5]) :
// ((fsmstat_nxtstat[0] == 1'b1) ? ~i_ROT20_n[4] : ~(i_ROT20_n[4] & i_ROT20_n[5]));
//full adder
wire fsmstat_fa_sum, fsmstat_fa_cout;
reg fsmstat_fa_cflag;
FA P56 (.i_A(fsmstat_var), .i_B(fsmstat_sr[0]), .i_CIN(fsmstat_fa_cflag), .o_S(fsmstat_fa_sum), .o_COUT(fsmstat_fa_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
fsmstat_fa_cflag <= fsmstat_fa_cout & i_ROT20_n[19];
end
end
//fsm state shift
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(fsmstat_shift == 1'b1) begin //shift
fsmstat_sr[2] <= fsmstat_fa_sum & i_SYS_RUN_FLAG;
fsmstat_sr[1:0] <= fsmstat_sr[2:1];
end
else begin //hold
fsmstat_sr[2] <= fsmstat_sr[2] & i_SYS_RUN_FLAG;
fsmstat_sr[1:0] <= fsmstat_sr[1:0];
end
end
end
//parallel load
reg [2:0] fsmstat_parallel = 3'b000;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[7] == 1'b0) begin //D-latch loads at nROT20[8]
fsmstat_parallel <= fsmstat_sr;
end
else begin
fsmstat_parallel <= fsmstat_parallel;
end
end
end
///////////////////////////////////////////////////////////
////// FSM FLAG
////
reg fsmflag;
always @(*) begin
case(fsmstat_parallel)
3'd0: fsmflag <= ~i_SUPBD_ACT_n;
3'd1: fsmflag <= i_OP_DONE;
3'd2: fsmflag <= 1'b0;
3'd3: fsmflag <= 1'b0;
3'd4: fsmflag <= i_PGCMP_EQ;
3'd5: fsmflag <= i_PGCMP_EQ;
3'd6: fsmflag <= 1'b0;
3'd7: fsmflag <= &{~i_ROT20_n[8], ~i_SUPBD_ACT_n, ~i_VALPG_ACC_FLAG, (i_PGREG_SR_SHIFT & i_MUXED_BDO_EN_DLYD), i_SUMEQ_n};
endcase
end
///////////////////////////////////////////////////////////
////// AND-OR MATRIX
////
wire [7:0] pla_output;
reg [1:0] command_a_en = 2'b00; //initialize output register
reg [1:0] command_b_en = 2'b00;
reg [1:0] command_a_0 = 2'b00; //command synchronizer chain: async input from CPU(RD/WR commands)
reg [1:0] command_b_0 = 2'b00;
reg [1:0] command_a_1 = 2'b00;
reg [1:0] command_b_1 = 2'b00;
K005297_fsm_pla pla_main
(
.i_A (i_CMDREG_RDREQ ), //CMDREG.RDREQ
.i_B (i_CMDREG_WRREQ ), //CMDREG.WRREQ
.i_C (fsmstat_parallel[0] ), //FSMSTAT.D0
.i_D (fsmstat_parallel[1] ), //FSMSTAT.D1
.i_E (fsmstat_parallel[2] ), //FSMSTAT.D2
.i_F (i_OP_DONE ), //OP_DONE
.i_G (fsmflag ), //FSMFLAGIN
.i_H (i_SYS_ERR_FLAG ), //SYS_ERR_FLAG
.o_S (pla_output[5] ),
.o_T (pla_output[4] ),
.o_U (pla_output[3] ),
.o_V (pla_output[2] ),
.o_W (pla_output[1] ),
.o_X (pla_output[0] ),
.o_Y (pla_output[7] ),
.o_Z (pla_output[6] )
);
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[9] == 1'b0) begin //D-latch loads at nROT20[10]
fsmstat_nxtstat <= pla_output[7:6];
end
end
end
wire r59 = pla_output[5] & ~pla_output[4] & ~pla_output[3];
//
// FSM COMMAND/ENABLE SYNCHRONIZER CHAIN(2)
//
//The FSM gets bubble RW command from the asynchronous latch and decodes it.
//Sample the value @ negedge ROT20_n[10] and shift it @ posedge ROT20_n[10].
//RW command output automatically disabled @ ROT20_n[10], so shifter's output
//can be presented @ posedge ROT20_n[10].
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[9] == 1'b0) begin //D-latch loads at nROT20[10]
command_a_en[0] <= pla_output[5];
command_a_en[1] <= 1'b0;
command_b_en[0] <= pla_output[2];
command_b_en[1] <= 1'b0;
end
else if(i_ROT20_n[10] == 1'b0) begin
command_a_en[1] <= command_a_en[0];
command_b_en[1] <= command_b_en[0];
end
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_ROT20_n[9] == 1'b0) begin //D-latch loads at nROT20[10]
command_a_0 <= pla_output[4:3];
command_b_0 <= pla_output[1:0];
end
else if(i_ROT20_n[10] == 1'b0) begin
command_a_1 <= command_a_0;
command_b_1 <= command_b_0;
end
end
end
///////////////////////////////////////////////////////////
////// COMMAND DECODER
////
assign o_CMDREG_RST_n = ~&{ command_a_1[1], command_a_1[0], command_a_en[1]}; //NAND /3'b111
assign o_FSMERR_RESTART_n = ~&{~command_a_1[1], command_a_1[0], command_a_en[1]}; //NAND /3'b101
assign o_BDI_EN_SET_n = ~&{ command_b_1[1], command_b_1[0], command_b_en[1]}; //NAND /3'b111
assign o_BDI_EN_RST_n = ~&{~command_b_1[1], command_b_1[0], command_b_en[1]}; //NAND /3'b101
assign o_PGREG_SRLD_EN = &{ command_a_1[1], ~command_a_1[0], command_a_en[1]}; //AND 3'b110
assign o_ACC_START = &{ command_b_1[1], ~command_b_1[0], command_b_en[1]}; //AND 3'b110
assign o_REP_START = &{~command_b_1[1], ~command_b_1[0], command_b_en[1]}; //AND 3'b100
assign o_CMD_ACCEPTED_n = ~&{~command_a_1[1], ~command_a_1[0], command_a_en[1]}; //NAND 3'b100 //NOR??
endmodule
module K005297_fsm_pla
(
input wire i_A,
input wire i_B,
input wire i_C,
input wire i_D,
input wire i_E,
input wire i_F,
input wire i_G,
input wire i_H,
output wire o_S,
output wire o_T,
output wire o_U,
output wire o_V,
output wire o_W,
output wire o_X,
output wire o_Y,
output wire o_Z
);
//internal wires
wire A = i_A; //CMDREG.RDREQ
wire B = i_B; //CMDREG.WRREQ
wire C = i_C; //FSMSTAT.D0
wire D = i_D; //FSMSTAT.D1
wire E = i_E; //FSMSTAT.D2
wire F = i_F; //F25/Q
wire G = i_G; //FSMFLAGIN
wire H = i_H; //SYS_ERR_FLAG
//AND array 1
wire S36 = &{ A, ~B, C, ~D, E, ~F, ~H };
wire S44 = &{ ~A, B, ~F, ~G };
wire S43 = &{ ~A, B, ~C, ~D, E, ~F, ~H };
wire R49 = &{ ~C, D, ~E, ~H };
wire S42 = &{ ~A, B, ~C, D, E, ~F, ~H };
wire R50 = &{ C, D, ~E, ~H };
wire S41 = &{ A, ~B, ~F, ~G };
wire S29 = &{ ~A, ~B, ~F, ~G };
wire R36 = &{ C, D, E, ~H };
wire S37 = &{ ~A, ~B, F, G };
//misc
wire S45 = S44 | S37; //~A
wire R33 = A ^ B;
//AND array 2
wire R35 = &{ ~D, ~E, ~H } & S29;
wire R32 = &{ ~A, B } & R36;
wire S31 = &{ ~G } & S43;
wire R29 = &{ A, ~B, ~F } & R36;
wire S30 = &{ ~G } & S36;
wire S27 = R49 & S29;
wire S50 = &{ ~A, ~B, ~C, ~D, ~E, H };
wire S49 = &{ ~A, ~B, ~C, ~D, ~E, ~F, G, ~H };
wire S46 = S44 & R50;
wire S38 = &{ G } & S36;
wire T42 = &{ ~G } & S42;
wire T40 = &{ G } & S43;
wire S48 = R49 & S41;
wire S47 = S44 & R49;
wire R52 = R50 & S41;
wire S51 = &{ C, ~D, ~E, ~H } & S45;
wire T41 = &{ G } & S42;
wire R34 = S29 & R36;
wire R37 = &{ C, D, E, H } & R33;
wire R30 = &{ A, ~B, F } & R36;
wire S40 = &{ C, ~D, ~E, H } & S29;
//OR array
wire S28 = |{R35, R32, S31, R29, S30, S27};
assign o_S = ~(|{S50, S49, S46, S38, T42, T40, R52, T41, R34} | S28);
assign o_T = ~ S40;
assign o_U = ~|{S48, S47};
assign o_V = ~(|{S49, T42, T40, T41, R34, S40} | S28);
assign o_W = ~|{S38, S47};
assign o_X = ~|{S46, S38, R52};
assign o_Y = ~|{S49, S46, T42, S48, S47, S51, T41, R34, R37, R30};
assign o_Z = ~|{S38, T40, R52, T41, R34, R37, R30, S40};
endmodule

View File

@@ -0,0 +1,128 @@
module K005297_functrig
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_HALT, //TST4
input wire i_SYS_RST_n,
input wire i_UMODE_n,
input wire i_CYCLECNTR_LSB,
input wire i_ACC_INVAL_n,
input wire i_PGCMP_EQ,
input wire i_SYNCTIP_n,
input wire i_BDI_EN,
output wire o_ACC_END,
output wire o_SWAP_START,
output wire o_ACQ_START,
output wire o_ADDR_RST
);
///////////////////////////////////////////////////////////
////// ACCESS TERMINATION
////
//terminates magnetic field roation after 7030us
wire const702 = ~&{i_ROT20_n[9], i_ROT20_n[7], i_ROT20_n[5], i_ROT20_n[4], i_ROT20_n[3], i_ROT20_n[2], i_ROT20_n[1]};
reg eq702_flag_n = 1'b1;
reg acc_end_flag_n = 1'b1;
assign o_ACC_END = ~acc_end_flag_n;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
eq702_flag_n <= (((i_CYCLECNTR_LSB | i_HALT) ^ const702) | eq702_flag_n | i_UMODE_n) & i_ROT20_n[19];
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
acc_end_flag_n <= (i_SYS_RST_n == 1'b0) ? 1'b1 :
(i_ROT20_n[10] == 1'b0) ? eq702_flag_n : acc_end_flag_n;
end
end
///////////////////////////////////////////////////////////
////// SWAP START
////
//turn on swap gate after 6240us
wire const623 = ~&{i_ROT20_n[9], i_ROT20_n[6], i_ROT20_n[5], i_ROT20_n[3], i_ROT20_n[2], i_ROT20_n[1], i_ROT20_n[0]};
reg eq623_flag_n = 1'b1;
reg swap_start_flag_n = 1'b1;
assign o_SWAP_START = ~swap_start_flag_n;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
eq623_flag_n <= (((i_CYCLECNTR_LSB | i_HALT) ^ const623) | eq623_flag_n) & i_ROT20_n[19];
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
swap_start_flag_n <= (i_BDI_EN == 1'b1) ? 1'b1 :
(i_ROT20_n[10] == 1'b0) ? eq623_flag_n : swap_start_flag_n;
end
end
///////////////////////////////////////////////////////////
////// ACQUISITION START
////
//start bubble data acquisition after 980us
wire const97 = ~&{i_ROT20_n[6], i_ROT20_n[5], i_ROT20_n[0]};
reg eq97_flag_n = 1'b1;
reg acq_start_flag_n = 1'b1;
wire acq_start_flag_feedback = (i_SYS_RST_n == 1'b0) ? 1'b1 :
(i_ROT20_n[10] == 1'b0) ? (eq97_flag_n | ~i_BDI_EN) : acq_start_flag_n;
assign o_ACQ_START = ~acq_start_flag_n;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
eq97_flag_n <= (((i_CYCLECNTR_LSB | i_HALT) ^ const97) | eq97_flag_n | i_UMODE_n) & i_ROT20_n[19];
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
acq_start_flag_n <= (|{~i_ACC_INVAL_n, i_BDI_EN, ~i_PGCMP_EQ, i_ROT20_n[14]} & i_SYNCTIP_n) & acq_start_flag_feedback;
end
end
//delayed ~ROT20_n[18] ...why not D19?
reg rot20_d18_dlyd;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
rot20_d18_dlyd <= ~i_ROT20_n[18];
end
end
assign o_ADDR_RST = o_ACQ_START & rot20_d18_dlyd;
endmodule

View File

@@ -0,0 +1,48 @@
module K005297_invalpgdet
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_TST, //test pin(normally 1)
input wire i_PGREG_SR_LSB, //page number shift register's lsb
input wire i_INVALPG_LSB, //invalid page reference point
input wire i_UMODE_n,
input wire i_PGCMP_EQ,
//output
output wire o_ACC_INVAL_n,
output wire o_VALPG_FLAG_SET_n
);
///////////////////////////////////////////////////////////
////// INVALID PAGE DETECTOR
////
//invalid page
reg invalid_page = 1'b0;
reg access_invalid_n = 1'b1;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
//TST3 = 1: eq 0
//TST3 = 0: gte INVALPG
invalid_page <= ~(~(((i_TST | i_INVALPG_LSB) & i_PGREG_SR_LSB) | ((i_TST | i_INVALPG_LSB | i_PGREG_SR_LSB) & invalid_page)) | ~i_ROT20_n[19]);
access_invalid_n <= (i_ROT20_n[12] == 1'b0) ? (invalid_page & ~i_UMODE_n) : (access_invalid_n & ~i_UMODE_n);
end
end
assign o_ACC_INVAL_n = access_invalid_n & i_PGCMP_EQ;
assign o_VALPG_FLAG_SET_n = ~(o_ACC_INVAL_n & ~i_ROT20_n[14]);
endmodule

View File

@@ -0,0 +1,115 @@
module K005297_invalpgdgen
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//control
input wire i_PGREG_D2,
input wire i_PGREG_D8,
input wire i_EFFBDO_EN,
input wire i_BDO_EN_n,
input wire i_GLCNT_RD,
input wire i_VALPG_ACC_FLAG,
input wire i_UMODE_n,
input wire i_SUPBD_ACT_n,
input wire i_SYNCED_FLAG,
input wire i_ALD_nB_U,
input wire i_BDI,
output wire o_MUXED_BDI,
output wire o_EFF_MUXED_BDI
);
///////////////////////////////////////////////////////////
////// INVALID PAGE DATA GENERATOR
////
//muxed bdi = bubble data + invalid page data
//effective muxed bdi = excepts supplementary bubble data
assign o_EFF_MUXED_BDI = o_MUXED_BDI & i_SUPBD_ACT_n;
//SR shift enable
wire sr8_last_shift; //shift flag
wire sr8_shift = (i_EFFBDO_EN & i_GLCNT_RD) | (i_BDO_EN_n & sr8_last_shift); //mux?
SRNAND F37 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[8]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(sr8_last_shift));
//shift register
reg [7:0] sr8;
wire sr8_msb;
wire sr8_lsb = sr8[0];
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(sr8_shift == 1'b1) begin
sr8[7] <= sr8_msb;
sr8[6:0] <= sr8[7:1];
end
else begin
sr8 <= sr8;
end
end
end
//adder
wire sr8_const, sr8_fa_sum, sr8_fa_cout; //FA carry out
reg sr8_fa_cflag = 1'b0; //FA carry storage
assign sr8_msb = (i_ALD_nB_U == 1'b0) ? sr8_fa_sum & i_SYNCED_FLAG : sr8_lsb & i_SYNCED_FLAG; //bootloader : user pages
FA Q59 (.i_A(o_EFF_MUXED_BDI), .i_B(sr8_lsb), .i_CIN(sr8_fa_cflag), .o_S(sr8_fa_sum), .o_COUT(sr8_fa_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(sr8_shift == 1'b1) begin
sr8_fa_cflag <= sr8_fa_cout & (i_SUPBD_ACT_n & ~i_ALD_nB_U);
end
else begin
sr8_fa_cflag <= sr8_fa_cflag & (i_SUPBD_ACT_n & ~i_ALD_nB_U);
end
end
end
//page number synchronizer(signal from true D-latch)
reg [1:0] sr8_bitmux_sel_0;
reg [1:0] sr8_bitmux_sel_1;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
sr8_bitmux_sel_0 <= {i_PGREG_D8, i_PGREG_D2};
sr8_bitmux_sel_1 <= sr8_bitmux_sel_0;
end
end
//sr8 bit selector for scrambling?
reg sr8_bitmux;
always @(*) begin
case(sr8_bitmux_sel_1)
2'b00: sr8_bitmux <= sr8[7];
2'b01: sr8_bitmux <= sr8[6];
2'b10: sr8_bitmux <= sr8[5];
2'b11: sr8_bitmux <= sr8[4];
endcase
end
assign o_MUXED_BDI = i_BDI ^ (sr8_bitmux & ~(i_VALPG_ACC_FLAG | i_UMODE_n | ~i_SUPBD_ACT_n));
endmodule

View File

@@ -0,0 +1,52 @@
module K005297_mskldtimer
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_4BEN_n,
input wire i_ACC_ACT_n,
input wire i_ACQ_MSK_LD,
output reg o_MSKREG_SR_LD = 1'b0
);
reg [3:0] mask_load_timer = 4'hF;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if((i_ACC_ACT_n | (o_MSKREG_SR_LD & ~i_ROT20_n[1])) == 1'b1) begin //reset
mask_load_timer <= 4'hF;
end
else begin
if(~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n)) == 1'b1) begin //0-5_10-15
if(mask_load_timer == 4'h0) begin
mask_load_timer <= 4'hF;
end
else begin
mask_load_timer <= mask_load_timer - 4'h1;
end
end
else begin
mask_load_timer <= mask_load_timer;
end
end
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
o_MSKREG_SR_LD <= ((i_ROT20_n[3] & i_ROT20_n[18]) == 1'b0) ? (&{~mask_load_timer} | i_ACQ_MSK_LD) : o_MSKREG_SR_LD;
end
end
endmodule

View File

@@ -0,0 +1,66 @@
module K005297_mskreg
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_4BEN_n,
input wire i_MSKREG_LD,
input wire i_MSKREG_SR_LD,
input wire i_BOOTEN_n,
//data
input wire [15:0] i_DIN,
//serial data
output wire o_MSKREG_SR_LSB
);
///////////////////////////////////////////////////////////
////// MASK REGISTER
////
//D latch * 16
wire [15:0] mskreg_q;
DL #(.dw(16)) MSKREG (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_EN(i_MSKREG_LD), .i_D(i_DIN), .o_Q(mskreg_q), .o_Q_n());
//mask register sr control
wire [1:0] mskreg_sr_ctrl; //11:hold(invalid), 10:load, 01:shift, 00:hold
assign mskreg_sr_ctrl[1] = ~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n)) & (i_MSKREG_SR_LD & i_BOOTEN_n); //0-5_10-15
assign mskreg_sr_ctrl[0] = ~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n)) & ~(i_MSKREG_SR_LD & i_BOOTEN_n);
//mask register sr
reg [15:0] mskreg_sr;
assign o_MSKREG_SR_LSB = mskreg_sr[0];
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
case(mskreg_sr_ctrl)
2'b11: begin
mskreg_sr <= mskreg_sr;
end
2'b10: begin //load
mskreg_sr <= mskreg_q;
end
2'b01: begin //shift
mskreg_sr[15] <= ~i_BOOTEN_n;
mskreg_sr[14:0] <= mskreg_sr[15:1];
end
2'b00: begin
mskreg_sr <= mskreg_sr;
end
endcase
end
end
endmodule

View File

@@ -0,0 +1,112 @@
module K005297_pgcmp
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_BDI_EN, //bubble input data enable
input wire i_PGREG_SR_LSB, //page number shift register's lsb
input wire i_ABSPGCNTR_LSB, //absolute page counter's lsb
input wire i_UMODE_n, //user mode flag
//output
output wire o_PGCMP_EQ
);
///////////////////////////////////////////////////////////
////// RELPAGE ABSPAGE CONVERTER
////
/*
use carry of relpg-1299 as a gte flag(>= 1299)
relative page 0-1298: carry of relpg-1299(unsigned relpg+2979) is 0, use relpg+754 as the abspg
relative page 1299-4095: carry of relpage-1299 is 1, use relpg-1299 as the abspg
relpg 1296 -> 1296-1299 C=0 -> 1296+754 = 2050(abspg)
relpg 1298 -> 1298-1299 C=0 -> 1298+754 = 2052(abspg)
relpg 1299 -> 1299-1299 C=1 -> 1299-1299 = 0(abspg)
relpg 1300 -> 1300-1299 C=1 -> 1230-1299 = 1(abspg)
relpg 2052 -> 2052-1299 C=1 -> 2052-1299 = 753(abspg)
relpg 2053(invalid) -> 2053-1299 C=1 -> 2053-1299 = 754(abspg)
*/
//sub1299
wire const2797 = ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[7], i_ROT20_n[6],
i_ROT20_n[5], i_ROT20_n[3], i_ROT20_n[2], i_ROT20_n[0]}; //12'b1010_1110_1101 = unsigned 2797/signed -1299
wire sub1299_cout, sub1299_sum;
reg sub1299_cflag = 1'b0;
reg gte1299_flag = 1'b0;
FA O28 (.i_A(i_PGREG_SR_LSB), .i_B(const2797), .i_CIN(sub1299_cflag), .o_S(sub1299_sum), .o_COUT(sub1299_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
sub1299_cflag <= sub1299_cout & i_ROT20_n[19];
end
end
//gte flag: greater than or equal to 1299
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
gte1299_flag <= (i_ROT20_n[12] == 1'b0) ? sub1299_cflag : gte1299_flag; //store bit 11's carry
end
end
//add754
wire const754 = ~&{i_ROT20_n[9], i_ROT20_n[7], i_ROT20_n[6],
i_ROT20_n[5], i_ROT20_n[4], i_ROT20_n[1]}; //12'b0010_1111_0010 = 754
wire add754_cout, add754_sum;
reg add754_cflag = 1'b0;
FA O29 (.i_A(const754), .i_B(add754_cflag), .i_CIN(i_PGREG_SR_LSB), .o_S(add754_sum), .o_COUT(add754_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
add754_cflag <= add754_cout & i_ROT20_n[19];
end
end
///////////////////////////////////////////////////////////
////// COMPARATOR
////
wire target_abspg = (i_BDI_EN == 1'b0) ? i_PGREG_SR_LSB :
(gte1299_flag == 1'b0) ? add754_sum : sub1299_sum;
wire abspg_comparator = target_abspg ^ i_ABSPGCNTR_LSB; //goes high if different bit exists(XOR)
///////////////////////////////////////////////////////////
////// FLAG BIT
////
reg delay0_n, pgcmp_eq_n;
assign o_PGCMP_EQ = ~pgcmp_eq_n;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
delay0_n <= (delay0_n | abspg_comparator) & i_ROT20_n[19];
pgcmp_eq_n <= (i_UMODE_n == 1'b1) ? 1'b1 :
(i_ROT20_n[12] == 1'b0) ? delay0_n : pgcmp_eq_n;
end
end
endmodule

View File

@@ -0,0 +1,77 @@
module K005297_pgreg
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//control
input wire i_PGREG_LD, //async
input wire i_PGREG_SR_LD_EN,
output wire o_PGREG_SR_SHIFT,
//data
input wire [15:0] i_DIN,
output wire o_PGREG_D2,
output wire o_PGREG_D8,
output wire o_PGREG_SR_LSB
);
///////////////////////////////////////////////////////////
////// PAGE REGISTER
////
//Pseudo D latch * 12
wire [11:0] pgreg_q;
DL #(.dw(12)) PGREG (.i_CLK(i_MCLK), .i_CEN_n(1'b0), .i_EN(i_PGREG_LD), .i_D(i_DIN[11:0]), .o_Q(pgreg_q), .o_Q_n());
//True D latch primitive
/*
reg [11:0] pgreg_q;
always @(*) begin
if(i_PGREG_LD == 1'b1) begin
pgreg_q <= i_DIN[11:0];
end
else begin
pgreg_q <= pgreg_q;
end
end
*/
assign o_PGREG_D2 = pgreg_q[2];
assign o_PGREG_D8 = pgreg_q[8];
//shift flag
SRNAND N28 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[12]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(o_PGREG_SR_SHIFT));
//page shift register
reg [11:0] pgsr = 12'h000;
assign o_PGREG_SR_LSB = pgsr[0];
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
case({(i_PGREG_SR_LD_EN & ~i_ROT20_n[19]), o_PGREG_SR_SHIFT})
2'b00: pgsr <= pgsr; //hold
2'b01: begin pgsr[10:0] <= pgsr[11:1]; pgsr[11] <= o_PGREG_SR_LSB & i_SYS_RST_n; end //shift
2'b10: pgsr <= pgreg_q; //load TEST//
2'b11: pgsr <= pgsr; //hold(invalid)
endcase
end
end
endmodule

View File

@@ -0,0 +1,180 @@
module ASYNCDLPS
(
input wire i_SET,
input wire i_EN,
input wire i_D,
output reg o_Q
);
always @(*) begin
if(i_SET) begin
o_Q <= 1'b1;
end
else begin
if(i_EN) begin
o_Q <= i_D;
end
else begin
o_Q <= o_Q;
end
end
end
endmodule
module SYNCDLPS
(
input wire i_CLK,
input wire i_SET,
input wire i_EN,
input wire i_D,
output reg o_Q
);
always @(posedge i_CLK) begin
if(i_SET) begin
o_Q <= 1'b1;
end
else begin
if(i_EN) begin
o_Q <= i_D;
end
else begin
o_Q <= o_Q;
end
end
end
endmodule
module DL #(parameter dw=1)
(
input wire i_CLK,
input wire i_CEN_n,
input wire i_EN,
input wire [dw-1:0] i_D,
output wire [dw-1:0] o_Q,
output wire [dw-1:0] o_Q_n
);
reg [dw-1:0] DFF;
wire [dw-1:0] OUTPUT = (i_EN == 1'b0) ? DFF : i_D;
assign o_Q = OUTPUT;
assign o_Q_n = ~OUTPUT;
always @(posedge i_CLK) begin
if(!i_CEN_n) begin
if(i_EN) begin
DFF <= i_D;
end
end
end
endmodule
module FA
(
input wire i_A,
input wire i_B,
input wire i_CIN,
output wire o_S,
output wire o_COUT
);
assign o_S = (i_CIN == 1'b0) ? (i_A ^ i_B) : ~(i_A ^ i_B);
assign o_COUT = (i_CIN == 1'b0) ? (i_A & i_B) : (i_A | i_B);
endmodule
module SRNAND
(
input wire i_CLK,
input wire i_CEN_n,
input wire i_S_n,
input wire i_R_n,
output wire o_Q,
output wire o_Q_n
);
reg DFF = 1'b1;
reg Q;
assign o_Q = Q;
assign o_Q_n = ~Q;
always @(posedge i_CLK) begin
if(!i_CEN_n) begin
case({i_S_n, i_R_n})
2'b00: DFF <= DFF; //hold(illegal)
2'b01: DFF <= 1'b1; //set
2'b10: DFF <= 1'b0; //reset
2'b11: DFF <= DFF; //hold
endcase
end
end
always @(*) begin
case({i_S_n, i_R_n, DFF})
3'b000: Q <= DFF; //illegal
3'b001: Q <= DFF; //illegal
3'b010: Q <= 1'b1; //set인데 DFF가 0인경우
3'b011: Q <= DFF; //set이고 DFF가 1인경우
3'b100: Q <= DFF; //reset이고 DFF가 0인경우
3'b101: Q <= 1'b0; //reset인데 DFF가 1인경우
3'b110: Q <= DFF; //유지
3'b111: Q <= DFF; //유지
endcase
end
endmodule
module SRNOR
(
input wire i_CLK,
input wire i_CEN_n,
input wire i_S,
input wire i_R,
output wire o_Q,
output wire o_Q_n
);
reg DFF = 1'b1;
reg Q;
assign o_Q = Q;
assign o_Q_n = ~Q;
always @(posedge i_CLK) begin
if(!i_CEN_n) begin
case({i_S, i_R})
2'b00: DFF <= DFF; //hold
2'b01: DFF <= 1'b0; //reset
2'b10: DFF <= 1'b1; //set
2'b11: DFF <= DFF; //hold(illegal)
endcase
end
end
always @(*) begin
case({i_S, i_R, DFF})
3'b000: Q <= DFF; //유지
3'b001: Q <= DFF; //유지
3'b010: Q <= DFF; //reset이고 DFF가 0인경우
3'b011: Q <= 1'b0; //reset인데 DFF가 1인경우
3'b100: Q <= 1'b1; //set인데 DFF가 0인경우
3'b101: Q <= DFF; //set이고 DFF가 1인경우
3'b110: Q <= DFF; //illegal
3'b111: Q <= DFF; //illegal
endcase
end
endmodule

View File

@@ -0,0 +1,93 @@
module K005297_relpgcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_RELPGCNTR_CNT_STOP,
input wire i_RELPGCNTR_CNT_START,
input wire i_ALD_nB_U,
output wire o_RELPGCNTR_LSB
);
///////////////////////////////////////////////////////////
////// RELATIVE PAGE COUNTER
////
/*
gte(greater than or equal) flag(>= 1531 evaluation)
relative page 0-1530: +522
relative page 1531-2052: -1531(loop)
*/
//SR shift enable
wire relpgcntr_shift; //shift flag
SRNAND I24 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[12]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(relpgcntr_shift));
//const add enable
wire relpgcntr_add_en;
SRNOR I34 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S(i_RELPGCNTR_CNT_STOP), .i_R(i_RELPGCNTR_CNT_START), .o_Q(), .o_Q_n(relpgcntr_add_en));
reg [11:0] relpgcntr = 12'd0; //abs page counter
wire relpgcntr_const, relpgcntr_fa_sum, relpgcntr_fa_cout; //FA carry out
reg relpgcntr_fa_cflag = 1'b0; //FA carry storage
assign o_RELPGCNTR_LSB = relpgcntr_fa_sum & i_ALD_nB_U;
//shift register
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(relpgcntr_shift == 1'b1) begin
relpgcntr[11] <= o_RELPGCNTR_LSB;
relpgcntr[10:0] <= relpgcntr[11:1];
end
else begin
relpgcntr <= relpgcntr;
end
end
end
//constant generator: +522 or -1531
wire constP522 = ~&{i_ROT20_n[9], i_ROT20_n[3], i_ROT20_n[1]};
wire constN1531 = ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]};
reg gte1531_evalreg = 1'b0;
reg gte1531_flag = 1'b0;
assign relpgcntr_const = (gte1531_flag == 1'b0) ? constP522 : constN1531;
//+522 : -1531
//evaluator: greater than or equal to 1531
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
gte1531_evalreg <= ((relpgcntr_fa_sum & ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]}) |
((o_RELPGCNTR_LSB | ~&{i_ROT20_n[11], i_ROT20_n[9], i_ROT20_n[2], i_ROT20_n[0]}) & gte1531_evalreg)) &
i_ROT20_n[19];
gte1531_flag <= (i_ROT20_n[12] == 1'b0) ? gte1531_evalreg : gte1531_flag;
end
end
//adder
FA J30 (.i_A(relpgcntr_add_en & relpgcntr_const), .i_B(relpgcntr_fa_cflag), .i_CIN(relpgcntr[0]), .o_S(relpgcntr_fa_sum), .o_COUT(relpgcntr_fa_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
relpgcntr_fa_cflag <= relpgcntr_fa_cout & i_ROT20_n[19];
end
end
endmodule

View File

@@ -0,0 +1,91 @@
module K005297_spdet
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//control
input wire i_BDI, //bubble input data stream
input wire i_GLCNT_RD, //good loop count
input wire i_BOOTEN_n, //bootloader enable(bubble cartridge)
input wire i_BSEN_n, //bubble shift enable(bc)
input wire i_4BEN_n,
//output
output wire o_SYNCTIP_n,
output wire o_SYNCED_FLAG,
output wire o_SYNCED_FLAG_SET_n
);
//zero bit counter: needs 128 zero bits + 1 "one" bit
reg [7:0] zerobit_cntr = 8'd255;
wire zerobit_cntr_rst;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(zerobit_cntr_rst == 1'b1) begin
zerobit_cntr <= 8'd255;
end
else begin
if(i_GLCNT_RD == 1'b1) begin
if(zerobit_cntr == 8'd0) begin //loop counter
zerobit_cntr <= 8'd255;
end
else begin
zerobit_cntr <= zerobit_cntr - 8'd1;
end
end
else begin //hold
zerobit_cntr <= zerobit_cntr;
end
end
end
end
//invalid pattern: reset the counter if "one" comes in before a complete pattern is detected
reg invalid_pattern = 1'b1;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
invalid_pattern <= (i_GLCNT_RD == 1'b0) ? invalid_pattern : i_BDI; //0:1
end
end
//zero bit counter reset and synced flag SR latch
wire synced_flag;
assign o_SYNCED_FLAG_SET_n = i_BOOTEN_n | o_SYNCTIP_n;
assign zerobit_cntr_rst = i_BSEN_n | synced_flag | invalid_pattern; //resets zerobit counter
assign o_SYNCED_FLAG = synced_flag;
SRNAND D60 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_SYNCED_FLAG_SET_n), .i_R_n(i_SYS_RST_n), .o_Q(synced_flag), .o_Q_n());
//sync tip
wire synctip_en = (i_4BEN_n == 1'b0) ? ~i_ROT20_n[18] : ~i_ROT20_n[8]; //4bit mode : 2bit mode
wire synctip_4b = ~&{synctip_en, i_BDI, ~zerobit_cntr[7]}; //D51 TFF
reg [7:0] synctip_2b_dlyd;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
synctip_2b_dlyd[7] <= synctip_4b;
synctip_2b_dlyd[6:0] <= synctip_2b_dlyd[7:1];
end
end
assign o_SYNCTIP_n = (i_4BEN_n == 1'b0) ? synctip_4b : synctip_2b_dlyd[0]; //4bit mode : 2bit mode
endmodule

View File

@@ -0,0 +1,124 @@
module K005297_sumcmp
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//data in
input wire i_EFF_MUXED_BDI,
//control
input wire i_UMODE_n,
input wire i_BDO_EN_n,
input wire i_EFFBDO_EN,
input wire i_GLCNT_RD,
input wire i_PGREG_SR_SHIFT,
input wire i_DMADREG_BDLD_EN,
input wire i_MUXED_BDO_EN_DLYD,
input wire i_SUPBD_ACT_n,
input wire i_ALD_nB_U,
//output
output wire o_INVALPG_LSB,
output reg o_SUMEQ_n
);
//
// VARIABLE
//
//variable shift register
reg [11:0] sr_var = 12'h000;
wire sr_var_shift = (i_EFFBDO_EN & i_GLCNT_RD) | (i_BDO_EN_n & i_PGREG_SR_SHIFT);
//sr_var serial FA
wire sr_var_fa_sum, sr_var_fa_cout; //FA carry out
reg sr_var_fa_cflag = 1'b0; //FA carry storage
//msb/lsb
wire sr_var_msb = sr_var_fa_sum & i_MUXED_BDO_EN_DLYD;
wire sr_var_lsb = (i_UMODE_n == 1'b1) ? sr_var[0] : sr_var[4]; //bootloader:user page
//Full adder
FA N48 (.i_A(i_EFF_MUXED_BDI), .i_B(sr_var_fa_cflag), .i_CIN(sr_var_lsb), .o_S(sr_var_fa_sum), .o_COUT(sr_var_fa_cout));
//carry storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
sr_var_fa_cflag <= (sr_var_shift == 1'b1) ? (sr_var_fa_cout & ~i_DMADREG_BDLD_EN) : (sr_var_fa_cflag & ~i_DMADREG_BDLD_EN); //update:hold
end
end
//sr
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(sr_var_shift == 1'b1) begin
sr_var[11] <= sr_var_msb;
sr_var[10:0] <= sr_var[11:1];
end
else begin
sr_var <= sr_var;
end
end
end
//
// CONSTANT
//
//constant shift register
reg [11:0] sr_const = 12'h000;
wire sr_const_shift;
//msb in
wire sr_const_msb = (&{i_MUXED_BDO_EN_DLYD, i_PGREG_SR_SHIFT, ~i_SUPBD_ACT_n, ~i_ALD_nB_U} == 1'b1) ? sr_var_lsb : sr_const[0]; //load : hold
wire sr_const_lsb = sr_const[0];
assign o_INVALPG_LSB = sr_const_lsb;
//shift
SRNAND O35 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[12]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(sr_const_shift));
//sr
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(sr_const_shift == 1'b1) begin
sr_const[11] <= sr_const_msb;
sr_const[10:0] <= sr_const[11:1];
end
else begin
sr_const <= sr_const;
end
end
end
//
// COMPARATOR
//
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
o_SUMEQ_n <= ((sr_var_lsb ^ sr_const_lsb) | o_SUMEQ_n) & i_ROT20_n[19];
end
end
endmodule

View File

@@ -0,0 +1,84 @@
module K005297_supbdlcntr
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//control
input wire i_SYS_RUN_FLAG,
input wire i_4BEN_n,
input wire i_BDI_EN,
input wire i_SUPBD_START_n,
input wire i_MSKREG_SR_LSB,
input wire i_GLCNT_RD,
output wire o_SUPBDLCNTR_CNT,
output wire o_SUPBD_ACT_n,
output wire o_SUPBD_END_n
);
///////////////////////////////////////////////////////////
////// SUPPLEMENTARY BUBBLE DATA LENGTH COUNTER
////
//count enable
SRNAND J34 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_SUPBD_END_n), .i_R_n(i_SUPBD_START_n), .o_Q(o_SUPBD_ACT_n), .o_Q_n());
//delay something?
reg supbd_act_n_dlyd = 1'b1;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n)) == 1'b1) begin //0-5_10-15
supbd_act_n_dlyd <= o_SUPBD_ACT_n;
end
else begin
supbd_act_n_dlyd <= supbd_act_n_dlyd;
end
end
end
//supplementary data count up
wire glcnt_wr = ((~supbd_act_n_dlyd | o_SUPBD_ACT_n) & ~(i_ROT20_n[3] & i_ROT20_n[8] & ~(~(i_ROT20_n[13] & i_ROT20_n[18]) & ~i_4BEN_n)) & i_MSKREG_SR_LSB);
assign o_SUPBDLCNTR_CNT = (i_BDI_EN == 1'b0) ? glcnt_wr : i_GLCNT_RD;
//supplementary data bit counter
reg [3:0] supbd_length_cntr = 4'hF;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(o_SUPBD_ACT_n == 1'b1) begin //reset
supbd_length_cntr <= 4'hF;
end
else begin
if(o_SUPBDLCNTR_CNT == 1'b1) begin
if(supbd_length_cntr == 4'h0) begin
supbd_length_cntr <= 4'hF;
end
else begin
supbd_length_cntr <= supbd_length_cntr - 4'h1;
end
end
else begin
supbd_length_cntr <= supbd_length_cntr;
end
end
end
end
//flag
wire eq14 = (supbd_length_cntr == 4'h1) ? 1'b1 : 1'b0; //4'd14
assign o_SUPBD_END_n = (~(eq14 & ~(i_ROT20_n[0] & i_ROT20_n[5] & ~(~(i_ROT20_n[10] & i_ROT20_n[15]) & ~i_4BEN_n))) & i_SYS_RUN_FLAG); //0-5_10-15
endmodule

View File

@@ -0,0 +1,291 @@
module K005297_supervisor
(
//master clock
input wire i_MCLK,
//chip clock from bubble cart, synchronized to i_MCLK
input wire i_CLK4M_PCEN_n,
//master reset
input wire i_MRST_n,
//halt
input wire i_HALT_n,
//subclock control
input wire i_CLK2M_STOPRQ0_n,
input wire i_CLK2M_STOPRQ1_n,
output wire o_CLK2M_STOP_n,
output wire o_CLK2M_STOP_DLYD_n,
output wire o_CLK2M_PCEN_n,
//rotators
output wire [7:0] o_ROT8,
output wire [19:0] o_ROT20_n,
//system flags
output wire o_SYS_RST_n,
output wire o_SYS_RUN_FLAG,
output wire o_SYS_RUN_FLAG_SET_n
);
/*
CLOCKING INFORMATION
4MHz _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
NCLK
orig in _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
stage 0 ¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|________
stage 5 __________|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯
0 AND 5 _______________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|
PCLK
orig in ¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|________
stage 0 _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
stage 5 ¯¯¯¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_____
0 AND 5 _______|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|_____
4MHz _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
4M NCLK _______________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|
4M PCLK _______|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|_____
ROT8 -(7)---|------(0)------|------(1)------|------(2)------|------(3)------|------(4)------|------(5)------|----(6)-
ROT8[0] _______|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________________________________________________________________________________________
C2STOPDLYn _______|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
A59 OUT ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯
A60 OUT _______________________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________
A62 EN _______________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|
A62 OUT _______________________________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
A60 _______________________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________
A62 _______________________________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
A64(01)PCLK _______________________________________|¯¯¯¯¯¯¯|_______________________|¯¯¯¯¯¯¯|_______________________|¯¯¯¯¯¯¯|
A66(10)NCLK _______________________|¯¯¯¯¯¯¯|_______________________|¯¯¯¯¯¯¯|_______________________|¯¯¯¯¯¯¯|________________
4MHz _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
2MHz ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯
4MHz _______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|
2MHz ¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_______________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________
ROT8 -(7)---|------(0)------|------(1)------|------(2)------|------(3)------|------(4)------|------(5)------|----(6)-
PORCNTR -----------------(7)-------------------|-------------------------------------(6)--------------------------------
4M PCLK _______|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|____________|¯¯|_____
C2RDYn ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|__|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
OPSTOP ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________________________________________________________________________
ROT20n -----------------------(invalid)-----------------------|--------------(0)--------------|--------------(1)-------
*/
///////////////////////////////////////////////////////////
////// GLOBAL CLOCKS / FLAGS
////
//all stoarge elements works at falling edge of 4M/2M
wire CLK4P_n = i_CLK4M_PCEN_n; //4MHz clock from bubble memory cartridge 12MHz/3
wire CLK2P_n; //2MHz internal subclock that can be controlled by start/stop logic
///////////////////////////////////////////////////////////
////// MODULE ROT8
////
K005297_supervisor_rot8 rot8_main (.i_CLK(i_MCLK), .i_CEN_n(CLK4P_n), .i_STOP_n(i_HALT_n), .o_ROT8(o_ROT8)); //FREE-RUNNING 8-BIT ROTATOR, rotates bit 1 from LSB to MSB
///////////////////////////////////////////////////////////
////// CLK2M(SUBCLK) CONTROL/GENERATOR
////
//subclk control
//SYS_RUN_FLAG가 0이면 clk2m시동을 걸어줌, 1로 올라간 후에는 clk2m정지 플래그들이 제어
wire clk2m_ctrl = &{i_MRST_n, i_CLK2M_STOPRQ0_n, i_CLK2M_STOPRQ1_n} | ~o_SYS_RUN_FLAG; //A37 A36 A38
reg A41 = 1'b0;
wire clk2m_stop_n = i_MRST_n & A41;
wire clk2m_stop_dlyd_n;
assign o_CLK2M_STOP_n = clk2m_stop_n;
assign o_CLK2M_STOP_DLYD_n = clk2m_stop_dlyd_n;
always @(posedge i_MCLK) begin
if(!CLK4P_n) begin
A41 <= (o_ROT8[5] == 1'b0) ? A41 : clk2m_ctrl; //MUX 0:1
end
end
DL A42 (.i_CLK(i_MCLK), .i_CEN_n(CLK4P_n), .i_EN(o_ROT8[0]), .i_D(clk2m_stop_n), .o_Q(clk2m_stop_dlyd_n), .o_Q_n());
//subclk generator
//negative clock enable신호 생성
reg A59 = 1'b0;
always @(posedge i_MCLK) begin
if(!CLK4P_n) begin
A59 <= ~(A59 & clk2m_stop_dlyd_n); //1이면 flip, 0이면 1유지
end
end
assign CLK2P_n = (A59 | CLK4P_n);
assign o_CLK2M_PCEN_n = CLK2P_n;
///////////////////////////////////////////////////////////
////// POR CONTROL
////
//this counter is for ring counter synchronization; they follow the order below:
//rot8 4 5 6 7 0 1 2 3 4 5 6 7
//rot20 0 1 2 3 4 5
reg [3:0] por_cntr = 4'b1111; //cascaded T flip flops; A23 A24 A25 A27
always @(posedge i_MCLK) begin
if(!CLK4P_n) begin
if(~clk2m_stop_dlyd_n == 1'b1) begin //set
por_cntr <= 4'b1111;
end
else begin
if(~o_ROT8[1] == 1'b0) begin //count
if(por_cntr == 4'b0000) begin
por_cntr <= 4'b1111; //loop
end
else begin
por_cntr <= por_cntr - 4'b1;
end
end
else begin
por_cntr <= por_cntr; //hold
end
end
end
end
wire op_start_n = ~&{o_ROT8[0], por_cntr[3:1], ~por_cntr[0]}; //A22
wire op_stop;
wire clk2m_ready_n = ~&{~por_cntr[3], ~por_cntr[0]}; //A29
wire A30Q;
assign op_stop = ~A30Q;
SRNAND A30 (.i_CLK(i_MCLK), .i_CEN_n(CLK4P_n), .i_S_n(clk2m_ready_n), .i_R_n(clk2m_stop_n), .o_Q(A30Q), .o_Q_n());
SRNAND A21 (.i_CLK(i_MCLK), .i_CEN_n(CLK4P_n), .i_S_n(op_start_n), .i_R_n(A30Q), .o_Q(o_SYS_RST_n), .o_Q_n());
///////////////////////////////////////////////////////////
////// MODULE ROT20
////
K005297_supervisor_rot20 rot20_main (.i_CLK(i_MCLK), .i_CEN_n(CLK2P_n), .i_STOP(op_stop), .o_ROT20_n(o_ROT20_n)); //20-BIT ROTATOR, rotates bit 1 from LSB to MSB
///////////////////////////////////////////////////////////
////// SYS_RUN_FLAG_n
////
assign o_SYS_RUN_FLAG_SET_n = ~(o_SYS_RST_n & ~o_ROT20_n[19]);
SRNAND C30 (.i_CLK(i_MCLK), .i_CEN_n(CLK4P_n), .i_S_n(o_SYS_RST_n), .i_R_n(o_SYS_RUN_FLAG_SET_n), .o_Q(), .o_Q_n(o_SYS_RUN_FLAG));
///////////////////////////////////////////////////////////
////// RING COUNTER DECODER
////
reg [4:0] debug_rot20_val;
reg [2:0] debug_rot8_val;
always @(*) begin
case(o_ROT20_n)
20'b1111_1111_1111_1111_1110: debug_rot20_val <= 5'd0;
20'b1111_1111_1111_1111_1101: debug_rot20_val <= 5'd1;
20'b1111_1111_1111_1111_1011: debug_rot20_val <= 5'd2;
20'b1111_1111_1111_1111_0111: debug_rot20_val <= 5'd3;
20'b1111_1111_1111_1110_1111: debug_rot20_val <= 5'd4;
20'b1111_1111_1111_1101_1111: debug_rot20_val <= 5'd5;
20'b1111_1111_1111_1011_1111: debug_rot20_val <= 5'd6;
20'b1111_1111_1111_0111_1111: debug_rot20_val <= 5'd7;
20'b1111_1111_1110_1111_1111: debug_rot20_val <= 5'd8;
20'b1111_1111_1101_1111_1111: debug_rot20_val <= 5'd9;
20'b1111_1111_1011_1111_1111: debug_rot20_val <= 5'd10;
20'b1111_1111_0111_1111_1111: debug_rot20_val <= 5'd11;
20'b1111_1110_1111_1111_1111: debug_rot20_val <= 5'd12;
20'b1111_1101_1111_1111_1111: debug_rot20_val <= 5'd13;
20'b1111_1011_1111_1111_1111: debug_rot20_val <= 5'd14;
20'b1111_0111_1111_1111_1111: debug_rot20_val <= 5'd15;
20'b1110_1111_1111_1111_1111: debug_rot20_val <= 5'd16;
20'b1101_1111_1111_1111_1111: debug_rot20_val <= 5'd17;
20'b1011_1111_1111_1111_1111: debug_rot20_val <= 5'd18;
20'b0111_1111_1111_1111_1111: debug_rot20_val <= 5'd19;
endcase
case(o_ROT8)
8'b0000_0001: debug_rot8_val <= 3'd0;
8'b0000_0010: debug_rot8_val <= 3'd1;
8'b0000_0100: debug_rot8_val <= 3'd2;
8'b0000_1000: debug_rot8_val <= 3'd3;
8'b0001_0000: debug_rot8_val <= 3'd4;
8'b0010_0000: debug_rot8_val <= 3'd5;
8'b0100_0000: debug_rot8_val <= 3'd6;
8'b1000_0000: debug_rot8_val <= 3'd7;
endcase
end
endmodule
module K005297_supervisor_rot8
(
input wire i_CLK,
input wire i_CEN_n,
input wire i_STOP_n,
output wire [7:0] o_ROT8
);
reg [7:0] SR8 = 8'b0;
assign o_ROT8 = SR8;
always @(posedge i_CLK) begin
if(~i_CEN_n) begin
SR8[7:1] <= SR8[6:0];
SR8[0] <= ~|{SR8[6:0], ~i_STOP_n}; //A55 NOT
end
end
endmodule
module K005297_supervisor_rot20
(
input wire i_CLK,
input wire i_CEN_n,
input wire i_STOP,
output wire [19:0] o_ROT20_n
);
reg [19:0] SR20 = 20'b0000_0001_0000_0010_0000;
assign o_ROT20_n = ~SR20;
always @(posedge i_CLK) begin
if(~i_CEN_n) begin
SR20[19:1] <= SR20[18:0];
SR20[0] <= ~|{SR20[18:0], i_STOP};
end
end
endmodule

View File

@@ -0,0 +1,49 @@
module K005297_tempdet
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//control
input wire i_TEMPLO_n,
input wire i_CLK2M_STOP_n,
input wire i_CLK2M_STOP_DLYD_n,
output wire o_TEMPDROP_SET_n,
output wire o_HEATEN_n
);
//register for edge detection
reg edgedet_0, edgedet_1;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
edgedet_0 <= i_CLK2M_STOP_n & i_TEMPLO_n;
edgedet_1 <= i_CLK2M_STOP_DLYD_n;
end
end
//TEMPDROP flag
assign o_TEMPDROP_SET_n = ~(edgedet_0 & ~(i_CLK2M_STOP_n & i_TEMPLO_n)); //negative edge detection
wire heaten_clr_n = ~(~edgedet_0 & (i_CLK2M_STOP_n & i_TEMPLO_n)) & i_CLK2M_STOP_n; //positive edge detection
wire heaten_set_n = ~((~edgedet_1 & i_CLK2M_STOP_DLYD_n & ~i_TEMPLO_n) & heaten_clr_n);
//delay
reg [1:0] heaten_ctrl_n;
always @(posedge i_MCLK) begin
if(!i_CLK4M_PCEN_n) begin
heaten_ctrl_n[1] <= heaten_clr_n;
heaten_ctrl_n[0] <= heaten_set_n;
end
end
//HEATEN_n out
SRNAND C20 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK4M_PCEN_n), .i_S_n(heaten_ctrl_n[1]), .i_R_n(heaten_ctrl_n[0]), .o_Q(o_HEATEN_n), .o_Q_n());
endmodule

View File

@@ -0,0 +1,107 @@
module K005297_timer25k
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//timer
input wire i_TIMER25K_CNT,
input wire i_TIMER25K_OUTLATCH_LD_n,
output wire o_TIMER25K_TIMEOVER_n,
output reg [11:0] o_TIMERREG_LSBS = 12'd0
);
///////////////////////////////////////////////////////////
////// 2556 TIMER(500ns*2556 = 1.278ms)
////
///////////////////////////////////////////////////////////
////// CYCLE COUNTER
////
/*
+1 serial up counter
*/
//shift flag
wire timer25k_shift;
SRNAND K3 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_ROT20_n[12]), .i_R_n(i_ROT20_n[0]), .o_Q(), .o_Q_n(timer25k_shift));
reg [11:0] timer25k = 12'd0; //timer
wire timer25k_fa_sum; //msb input
wire timer25k_fa_cout; //FA carry out
reg timer25k_fa_cflag = 1'b0; //FA carry storage
//serial full adder cell
FA K4 (.i_A(timer25k[0]), .i_B(timer25k_fa_cflag), .i_CIN((i_TIMER25K_CNT & ~i_ROT20_n[0])), .o_S(timer25k_fa_sum), .o_COUT(timer25k_fa_cout));
//previous carry bit storage
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
timer25k_fa_cflag <= timer25k_fa_cout & i_ROT20_n[19];
end
end
//shift register
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(timer25k_shift == 1'b1) begin
timer25k[11] <= timer25k_fa_sum & i_TIMER25K_CNT;
timer25k[10:0] <= timer25k[11:1];
end
else begin
timer25k <= timer25k;
end
end
end
/*
evaluation
*/
wire const2555 = ~&{i_ROT20_n[11], i_ROT20_n[8], i_ROT20_n[7], i_ROT20_n[6], i_ROT20_n[5], i_ROT20_n[4], i_ROT20_n[3], i_ROT20_n[1], i_ROT20_n[0]};
reg eq2555_flag_n = 1'b1;
reg timeover_flag_n = 1'b1;
assign o_TIMER25K_TIMEOVER_n = ~(~timeover_flag_n & ~i_ROT20_n[13]);
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
eq2555_flag_n <= ((timer25k_fa_sum ^ const2555) | eq2555_flag_n) & i_ROT20_n[19];
end
end
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
timeover_flag_n <= (i_ROT20_n[12] == 1'b0) ? eq2555_flag_n : timeover_flag_n;
end
end
/*
counter register
*/
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(i_TIMER25K_OUTLATCH_LD_n == 1'b0) begin
o_TIMERREG_LSBS <= timer25k;
end
end
end
endmodule

View File

@@ -0,0 +1,138 @@
module K005297_z14eval
(
//master clock
input wire i_MCLK,
//clock enables
input wire i_CLK4M_PCEN_n,
input wire i_CLK2M_PCEN_n,
//timing
input wire [19:0] i_ROT20_n,
//reset
input wire i_SYS_RST_n,
//lock control
input wire i_TIMER25K_TIMEOVER_n,
input wire i_Z14_ERR_n,
//lock flag related
output wire o_Z14_UNLOCK_n,
output wire o_Z14_LOCKED_n,
//control
input wire i_BDI_EN,
input wire i_SUPBD_ACT_n,
input wire i_SUPBD_END_n,
input wire i_DLCNT_START_n,
input wire i_SUPBDLCNTR_CNT,
input wire i_ACQ_START,
input wire i_MSKREG_SR_LSB,
input wire i_BDI,
input wire i_EFF_BDO,
output wire o_MUXED_BDO,
output wire o_TIMER25K_CNT,
output wire o_TIMER25K_OUTLATCH_LD_n,
//flags output
output wire o_Z14_n,
output wire o_Z11_d13_n,
output wire [3:0] o_TIMERREG_MSBS
);
reg rot20_d18_dlyd1, rot20_d18_dlyd2;
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
rot20_d18_dlyd1 <= ~i_ROT20_n[18];
rot20_d18_dlyd2 <= rot20_d18_dlyd1;
end
end
///////////////////////////////////////////////////////////
////// Z14 FLAG EVALUATOR
////
//Actually, this is a CRC14 calculator
//Z14 lock flag bit
assign o_Z14_UNLOCK_n = i_TIMER25K_TIMEOVER_n & o_Z11_d13_n;
//original implementation
assign o_TIMER25K_OUTLATCH_LD_n = o_Z14_LOCKED_n | o_Z11_d13_n;
SRNAND I7 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(o_Z14_UNLOCK_n), .i_R_n(i_Z14_ERR_n), .o_Q(o_Z14_LOCKED_n), .o_Q_n(o_TIMER25K_CNT));
//SR14 control
wire bdi_act, srctrl_en_n;
wire srctrl_shift = (bdi_act == 1'b1) ? i_SUPBDLCNTR_CNT : rot20_d18_dlyd2; //J47 AO22
SRNAND J48 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(i_SUPBD_END_n), .i_R_n(i_DLCNT_START_n), .o_Q(), .o_Q_n(bdi_act));
SRNAND F47 (.i_CLK(i_MCLK), .i_CEN_n(i_CLK2M_PCEN_n), .i_S_n(~(i_ACQ_START & ~i_ROT20_n[0]) & i_SYS_RST_n), .i_R_n(i_DLCNT_START_n), .o_Q(srctrl_en_n), .o_Q_n());
//SR14 data in
wire output_data_n = ~((~i_BDI_EN & i_EFF_BDO) | i_BDI); //M35
wire output_data_n_gated = ~(output_data_n | ~o_Z14_LOCKED_n); //M7
wire sr14_msb;
wire sr14_lsb = (sr14_msb ^ output_data_n_gated) & ~(~i_BDI_EN & ~i_SUPBD_ACT_n);
//SR14
reg [3:0] sr14_4;
reg sr14_1;
reg [8:0] sr14_9;
wire [13:0] sr14 = {sr14_9, sr14_1, sr14_4};
//MSB //LSB <- INPUT
wire [15:0] __DEBUG_CRC12_VAL = {sr14, 2'b00};
assign sr14_msb = sr14[13];
assign o_Z11_d13_n = |{sr14[13:3]} | i_ROT20_n[13];
assign o_Z14_n = |{sr14};
assign o_TIMERREG_MSBS = sr14[13:10];
always @(posedge i_MCLK) begin
if(!i_CLK2M_PCEN_n) begin
if(srctrl_en_n == 1'b1) begin //reset
sr14_4 <= 4'b0000;
sr14_1 <= 1'b0;
sr14_9 <= 9'b0_0000_0000;
end
else begin
if(srctrl_shift == 1'b1) begin //shift
//sr14_4
sr14_4[0] <= sr14_lsb;
sr14_4[3:1] <= sr14_4[2:0];
//sr14_1
sr14_1 <= sr14_4[3] ^ sr14_lsb;
//sr14_9
sr14_9[0] <= sr14_1 ^ sr14_lsb;
sr14_9[8:1] <= sr14_9[7:0];
end
else begin //hold
sr14_4 <= sr14_4;
sr14_1 <= sr14_1;
sr14_9 <= sr14_9;
end
end
end
end
//bubble data output
assign o_MUXED_BDO = ((~i_BDI_EN & ~i_SUPBD_ACT_n) == 1'b0) ? output_data_n_gated & i_MSKREG_SR_LSB : sr14_msb & i_MSKREG_SR_LSB;
endmodule

View File

@@ -0,0 +1,5 @@
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) fx68k.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) fx68kAlu.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) uaddrPla.sv ]
set_global_assignment -name SOURCE_FILE [file join $::quartus(qip_path) microrom.mem ]
set_global_assignment -name SOURCE_FILE [file join $::quartus(qip_path) nanorom.mem ]

2709
rtl/ipcores/fx68k/fx68k.sv Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
FX68K
68000 cycle accurate core
Copyright (c) 2018 by Jorge Cwik
fx68k@fxatari.com
FX68K is a 68K cycle exact compatible core. In theory at least, it should be impossible to distinguish functionally from a real 68K processor.
On Cyclone families it uses just over 5,100 LEs and about 5KB internal ram, reaching a max clock frequency close to 40MHz. Some optimizations are still possible to implement and increase the performance.
The core is fully synchronous. Considerable effort was done to avoid any asynchronous logic.
Written in SystemVerilog.
The timing of the external bus signals is exactly as the original processor. The only feature that is not implemented yet is bus retry using the external HALT input signal.
It was designed to replace an actual chip on a real board. This wasn't yet tested however and not all necessary output enable control signals are fully implemented.
Copyright
//
// 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/>.
//
Developer Notes
The core receives a clock that must be at least twice the frequency of the desired nominal speed. The core also receives two signals for masking both phases of the clock (PHI1 and PHI2). These signals are implemented as simple clock enable for all the flip flops used by the core. This way, the original clock frequency can be any multiple and it doesn't even need to be regular or constant.
These two signals are enPhi1 and enPhi2. They must be a single cycle pulse, and they don't need to be registered. Because they are actually used as clock enable, the output signals change one cycle later.
enPhi1 should be asserted one cycle before the high phase of the nominal clock, and enPhi2 one cycle before the low phase.
E.g., during a bus cycle, AS is asserted one cycle after enPhi1 is asserted, and AS is deasserted one cycle after enPhi2 is asserted. This follows the original bus timing that specify AS being asserted on the raising edge of the clock, and deasserted on the falling edge one.
All signals follow the original polarity and then most are low active.
extReset is external reset and is synchronous and high active. Hence is doesn't have to be registered.
pwrUp qualifies external reset as being a cold power up reset. If it is asserted, then extReset must be asserted as well. Most system don't need to distinguish between a cold and a warm reset at the CPU level. Then both signals can be always asserted together. The core does expect pwrUp to be asserted initially because there is no true asynchronous reset. The signal is high active.
Timing analysis
Microcode access is one of the slowest paths on the core. But the microcode output is not needed immediately. Use the following constraints to get a more accurate timing analysis. Note that the full path might need to be modified:
# Altera/Intel
set_multicycle_path -start -setup -from [get_keepers fx68k:fx68k|Ir[*]] -to [get_keepers fx68k:fx68k|microAddr[*]] 2
set_multicycle_path -start -hold -from [get_keepers fx68k:fx68k|Ir[*]] -to [get_keepers fx68k:fx68k|microAddr[*]] 1
set_multicycle_path -start -setup -from [get_keepers fx68k:fx68k|Ir[*]] -to [get_keepers fx68k:fx68k|nanoAddr[*]] 2
set_multicycle_path -start -hold -from [get_keepers fx68k:fx68k|Ir[*]] -to [get_keepers fx68k:fx68k|nanoAddr[*]] 1
# For Xilinx Vivado
set_multicycle_path -setup -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/nanoAddr_reg*/D] 2
set_multicycle_path -setup -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/microAddr_reg*/D] 2
set_multicycle_path -hold -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/nanoAddr_reg*/D] 1
set_multicycle_path -hold -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/microAddr_reg*/D] 1
The update of the CCR flags is also time critical. Some compilers might benefit with the following constraints, but this wasn't fully verified yet:
# Altera/Intel
# set_multicycle_path -start -setup -from [fx68k:fx68k|nanoLatch[*]]
# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 2
# set_multicycle_path -start -setup -from [fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|oper[*]]
# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 2
# set_multicycle_path -start -hold -from [fx68k:fx68k|nanoLatch[*]]
# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 1
# set_multicycle_path -start -hold -from [fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|oper[*]]
# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 1

View File

@@ -0,0 +1,839 @@
//
// FX 68K
//
// M68K cycle accurate, fully synchronous
// Copyright (c) 2018 by Jorge Cwik
//
// ALU
//
`timescale 1 ns / 1 ns
localparam MASK_NBITS = 5;
localparam
OP_AND = 1,
OP_SUB = 2, OP_SUBX = 3, OP_ADD = 4,
OP_EXT = 5, OP_SBCD = 6, OP_SUB0 = 7,
OP_OR = 8, OP_EOR = 9,
OP_SUBC = 10, OP_ADDC = 11, OP_ADDX = 12,
OP_ASL = 13,
OP_ASR = 14,
OP_LSL = 15,
OP_LSR = 16,
OP_ROL = 17,
OP_ROR = 18,
OP_ROXL = 19,
OP_ROXR = 20,
OP_SLAA = 21,
OP_ABCD = 22;
module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4,
input [15:0] ird,
input [2:0] aluColumn,
input [1:0] aluDataCtrl,
input aluAddrCtrl, alueClkEn, ftu2Ccr, init, finish, aluIsByte,
input [15:0] ftu,
input [15:0] alub,
input [15:0] iDataBus, input [15:0] iAddrBus,
output ze,
output reg [15:0] alue,
output reg [7:0] ccr,
output [15:0] aluOut);
`define ALU_ROW_01 16'h0002
`define ALU_ROW_02 16'h0004
`define ALU_ROW_03 16'h0008
`define ALU_ROW_04 16'h0010
`define ALU_ROW_05 16'h0020
`define ALU_ROW_06 16'h0040
`define ALU_ROW_07 16'h0080
`define ALU_ROW_08 16'h0100
`define ALU_ROW_09 16'h0200
`define ALU_ROW_10 16'h0400
`define ALU_ROW_11 16'h0800
`define ALU_ROW_12 16'h1000
`define ALU_ROW_13 16'h2000
`define ALU_ROW_14 16'h4000
`define ALU_ROW_15 16'h8000
// Bit positions for flags in CCR
localparam CF = 0, VF = 1, ZF = 2, NF = 3, XF = 4;
reg [15:0] aluLatch;
reg [4:0] pswCcr;
reg [4:0] ccrCore;
logic [15:0] result;
logic [4:0] ccrTemp;
reg coreH; // half carry latch
logic [15:0] subResult;
logic subHcarry;
logic subCout, subOv;
assign aluOut = aluLatch;
assign ze = ~ccrCore[ ZF]; // Check polarity !!!
//
// Control
// Signals derived from IRD *must* be registered on either T3 or T4
// Signals derived from nano rom can be registered on T4.
reg [15:0] row;
reg isArX; // Don't set Z
reg noCcrEn;
reg isByte;
reg [4:0] ccrMask;
reg [4:0] oper;
logic [15:0] aOperand, dOperand;
wire isCorf = ( aluDataCtrl == 2'b10);
wire [15:0] cRow;
wire cIsArX;
wire cNoCcrEn;
rowDecoder rowDecoder( .ird( ird), .row( cRow), .noCcrEn( cNoCcrEn), .isArX( cIsArX));
// Get Operation & CCR Mask from row/col
// Registering them on T4 increase performance. But slowest part seems to be corf !
wire [4:0] cMask;
wire [4:0] aluOp;
aluGetOp aluGetOp( .row, .col( aluColumn), .isCorf, .aluOp);
ccrTable ccrTable( .col( aluColumn), .row( row), .finish, .ccrMask( cMask));
// Inefficient, uCode could help !
wire shftIsMul = row[7];
wire shftIsDiv = row[1];
wire [31:0] shftResult;
reg [7:0] bcdLatch;
reg bcdCarry, bcdOverf;
reg isLong;
reg rIrd8;
logic isShift;
logic shftCin, shftRight, addCin;
// Register some decoded signals
always_ff @( posedge clk) begin
if( enT3) begin
row <= cRow;
isArX <= cIsArX;
noCcrEn <= cNoCcrEn;
rIrd8 <= ird[8];
isByte <= aluIsByte;
end
if( enT4) begin
// Decode if long shift
// MUL and DIV are long (but special !)
isLong <= (ird[7] & ~ird[6]) | shftIsMul | shftIsDiv;
ccrMask <= cMask;
oper <= aluOp;
end
end
always_comb begin
// Dest (addr) operand source
// If aluCsr (depends on column/row) addrbus is shifted !!
aOperand = (aluAddrCtrl ? alub : iAddrBus);
// Second (data,source) operand mux
case( aluDataCtrl)
2'b00: dOperand = iDataBus;
2'b01: dOperand = 'h0000;
2'b11: dOperand = 'hffff;
// 2'b10: dOperand = bcdResult;
2'b10: dOperand = 'X;
endcase
end
// Execution
// shift operand MSB. Input in ASR/ROL. Carry in right.
// Can't be registered because uses bus operands that aren't available early !
wire shftMsb = isLong ? alue[15] : (isByte ? aOperand[7] : aOperand[15]);
aluShifter shifter( .data( { alue, aOperand}),
.swapWords( shftIsMul | shftIsDiv),
.cin( shftCin), .dir( shftRight), .isByte( isByte), .isLong( isLong),
.result( shftResult));
wire [7:0] bcdResult;
wire bcdC, bcdV;
aluCorf aluCorf( .binResult( aluLatch[7:0]), .hCarry( coreH),
.bAdd( (oper != OP_SBCD) ), .cin( pswCcr[ XF]),
.bcdResult( bcdResult), .dC( bcdC), .ov( bcdV));
// BCD adjust is among the slowest processing on ALU !
// Precompute and register BCD result on T1
// We don't need to wait for execution buses because corf is always added to ALU previous result
always_ff @( posedge clk)
if( enT1) begin
bcdLatch <= bcdResult;
bcdCarry <= bcdC;
bcdOverf <= bcdV;
end
// Adder carry in selector
always_comb
begin
case( oper)
OP_ADD, OP_SUB: addCin = 1'b0;
OP_SUB0: addCin = 1'b1; // NOT = 0 - op - 1
OP_ADDC,OP_SUBC: addCin = ccrCore[ CF];
OP_ADDX,OP_SUBX: addCin = pswCcr[ XF];
default: addCin = 1'bX;
endcase
end
// Shifter carry in and direction selector
always_comb begin
case( oper)
OP_LSL, OP_ASL, OP_ROL, OP_ROXL, OP_SLAA: shftRight = 1'b0;
OP_LSR, OP_ASR, OP_ROR, OP_ROXR: shftRight = 1'b1;
default: shftRight = 1'bX;
endcase
case( oper)
OP_LSR,
OP_ASL,
OP_LSL: shftCin = 1'b0;
OP_ROL,
OP_ASR: shftCin = shftMsb;
OP_ROR: shftCin = aOperand[0];
OP_ROXL,
OP_ROXR:
if( shftIsMul)
shftCin = rIrd8 ? pswCcr[NF] ^ pswCcr[VF] : pswCcr[ CF];
else
shftCin = pswCcr[ XF];
OP_SLAA: shftCin = aluColumn[1]; // col4 -> 0, col 6-> 1
default: shftCin = 'X;
endcase
end
// ALU operation selector
always_comb begin
// sub is DATA - ADDR
mySubber( aOperand, dOperand, addCin,
(oper == OP_ADD) | (oper == OP_ADDC) | (oper == OP_ADDX),
isByte, subResult, subCout, subOv);
isShift = 1'b0;
case( oper)
OP_AND: result = aOperand & dOperand;
OP_OR: result = aOperand | dOperand;
OP_EOR: result = aOperand ^ dOperand;
OP_EXT: result = { {8{aOperand[7]}}, aOperand[7:0]};
OP_SLAA,
OP_ASL, OP_ASR,
OP_LSL, OP_LSR,
OP_ROL, OP_ROR,
OP_ROXL, OP_ROXR:
begin
result = shftResult[15:0];
isShift = 1'b1;
end
OP_ADD,
OP_ADDC,
OP_ADDX,
OP_SUB,
OP_SUBC,
OP_SUB0,
OP_SUBX: result = subResult;
OP_ABCD,
OP_SBCD: result = { 8'hXX, bcdLatch};
default: result = 'X;
endcase
end
task mySubber;
input [15:0] inpa, inpb;
input cin, bAdd, isByte;
output reg [15:0] result;
output cout, ov;
// Not very efficient!
logic [16:0] rtemp;
logic rm,sm,dm,tsm;
begin
if( isByte)
begin
rtemp = bAdd ? { 1'b0, inpb[7:0]} + { 1'b0, inpa[7:0]} + cin:
{ 1'b0, inpb[7:0] } - { 1'b0, inpa[7:0]} - cin;
result = { {8{ rtemp[7]}}, rtemp[7:0]};
cout = rtemp[8];
end
else begin
rtemp = bAdd ? { 1'b0, inpb } + { 1'b0, inpa} + cin:
{ 1'b0, inpb } - { 1'b0, inpa} - cin;
result = rtemp[ 15:0];
cout = rtemp[16];
end
rm = isByte ? rtemp[7] : rtemp[15];
dm = isByte ? inpb[ 7] : inpb[ 15];
tsm = isByte ? inpa[ 7] : inpa[ 15];
sm = bAdd ? tsm : ~tsm;
ov = (sm & dm & ~rm) | (~sm & ~dm & rm);
// Store half carry for bcd correction
subHcarry = inpa[4] ^ inpb[4] ^ rtemp[4];
end
endtask
// CCR flags process
always_comb begin
ccrTemp[XF] = pswCcr[XF]; ccrTemp[CF] = 0; ccrTemp[VF] = 0;
// Not on all operators
ccrTemp[ ZF] = isByte ? ~(| result[7:0]) : ~(| result);
ccrTemp[ NF] = isByte ? result[7] : result[15];
unique case( oper)
OP_EXT:
// Division overflow.
if( aluColumn == 5) begin
ccrTemp[VF] = 1'b1;
ccrTemp[NF] = 1'b1; ccrTemp[ ZF] = 1'b0;
end
OP_SUB0, // used by NOT
OP_OR,
OP_EOR:
begin
ccrTemp[CF] = 0; ccrTemp[VF] = 0;
end
OP_AND:
begin
// ROXL/ROXR indeed copy X to C in column 1 (OP_AND), executed before entering the loop.
// Needed when rotate count is zero, the ucode with the ROX operator never reached.
// C must be set to the value of X, X remains unaffected.
if( (aluColumn == 1) & (row[11] | row[8]))
ccrTemp[CF] = pswCcr[XF];
else
ccrTemp[CF] = 0;
ccrTemp[VF] = 0;
end
// Assumes col 3 of DIV use C and not X !
// V will be set in other cols (2/3) of DIV
OP_SLAA: ccrTemp[ CF] = aOperand[15];
OP_LSL,OP_ROXL:
begin
ccrTemp[ CF] = shftMsb;
ccrTemp[ XF] = shftMsb;
ccrTemp[ VF] = 1'b0;
end
OP_LSR,OP_ROXR:
begin
// 0 Needed for mul, or carry gets in high word
ccrTemp[ CF] = shftIsMul ? 1'b0 : aOperand[0];
ccrTemp[ XF] = aOperand[0];
// Not relevant for MUL, we clear it at mulm6 (1f) anyway.
// Not that MUL can never overlow!
ccrTemp[ VF] = 0;
// Z is checking here ALU (low result is actually in ALUE).
// But it is correct, see comment above.
end
OP_ASL:
begin
ccrTemp[ XF] = shftMsb; ccrTemp[ CF] = shftMsb;
// V set if msb changed on any shift.
// Otherwise clear previously on OP_AND (col 1i).
ccrTemp[ VF] = pswCcr[VF] | (shftMsb ^
(isLong ? alue[15-1] : (isByte ? aOperand[7-1] : aOperand[15-1])) );
end
OP_ASR:
begin
ccrTemp[ XF] = aOperand[0]; ccrTemp[ CF] = aOperand[0];
ccrTemp[ VF] = 0;
end
// X not changed on ROL/ROR !
OP_ROL: ccrTemp[ CF] = shftMsb;
OP_ROR: ccrTemp[ CF] = aOperand[0];
OP_ADD,
OP_ADDC,
OP_ADDX,
OP_SUB,
OP_SUBC,
OP_SUBX:
begin
ccrTemp[ CF] = subCout;
ccrTemp[ XF] = subCout;
ccrTemp[ VF] = subOv;
end
OP_ABCD,
OP_SBCD:
begin
ccrTemp[ XF] = bcdCarry;
ccrTemp[ CF] = bcdCarry;
ccrTemp[ VF] = bcdOverf;
end
endcase
end
// Core and psw latched at the same cycle
// CCR filter
// CCR out mux for Z & C flags
// Z flag for 32-bit result
// Not described, but should be used also for instructions
// that clear but not set Z (ADDX/SUBX/ABCD, etc)!
logic [4:0] ccrMasked;
always_comb begin
ccrMasked = (ccrTemp & ccrMask) | (pswCcr & ~ccrMask);
// if( finish | isCorf | isArX) // No need to check specicially for isCorf as they always have the "finish" flag anyway
if( finish | isArX)
ccrMasked[ ZF] = ccrTemp[ ZF] & pswCcr[ ZF];
end
always_ff @( posedge clk) begin
if( enT3) begin
// Update latches from ALU operators
if( (| aluColumn)) begin
aluLatch <= result;
coreH <= subHcarry;
// Update CCR core
if( (| aluColumn))
ccrCore <= ccrTemp; // Most bits not really used
end
if( alueClkEn)
alue <= iDataBus;
else if( isShift & (| aluColumn))
alue <= shftResult[31:16];
end
// CCR
// Originally on T3-T4 edge pulse !!
// Might be possible to update on T4 (but not after T0) from partial result registered on T3, it will increase performance!
if( pwrUp)
pswCcr <= '0;
else if( enT3 & ftu2Ccr)
pswCcr <= ftu[4:0];
else if( enT3 & ~noCcrEn & (finish | init))
pswCcr <= ccrMasked;
end
assign ccr = { 3'b0, pswCcr};
endmodule
// add bcd correction factor
// It would be more efficient to merge add/sub with main ALU !!!
module aluCorf( input [7:0] binResult, input bAdd, input cin, input hCarry,
output [7:0] bcdResult, output dC, output logic ov);
reg [8:0] htemp;
reg [4:0] hNib;
wire lowC = hCarry | (bAdd ? gt9( binResult[ 3:0]) : 1'b0);
wire highC = cin | (bAdd ? (gt9( htemp[7:4]) | htemp[8]) : 1'b0);
always_comb begin
if( bAdd) begin
htemp = { 1'b0, binResult} + (lowC ? 4'h6 : 4'h0);
hNib = htemp[8:4] + (highC ? 4'h6 : 4'h0);
ov = hNib[3] & ~binResult[7];
end
else begin
htemp = { 1'b0, binResult} - (lowC ? 4'h6 : 4'h0);
hNib = htemp[8:4] - (highC ? 4'h6 : 4'h0);
ov = ~hNib[3] & binResult[7];
end
end
assign bcdResult = { hNib[ 3:0], htemp[3:0]};
assign dC = hNib[4] | cin;
// Nibble > 9
function gt9 (input [3:0] nib);
begin
gt9 = nib[3] & (nib[2] | nib[1]);
end
endfunction
endmodule
module aluShifter( input [31:0] data,
input isByte, input isLong, swapWords,
input dir, input cin,
output logic [31:0] result);
// output reg cout
logic [31:0] tdata;
// size mux, put cin in position if dir == right
always_comb begin
tdata = data;
if( isByte & dir)
tdata[8] = cin;
else if( !isLong & dir)
tdata[16] = cin;
end
always_comb begin
// Reverse alu/alue position for MUL & DIV
// Result reversed again
if( swapWords & dir)
result = { tdata[0], tdata[31:17], cin, tdata[15:1]};
else if( swapWords)
result = { tdata[30:16], cin, tdata[14:0], tdata[31]};
else if( dir)
result = { cin, tdata[31:1]};
else
result = { tdata[30:0], cin};
end
endmodule
// Get current OP from row & col
module aluGetOp( input [15:0] row, input [2:0] col, input isCorf,
output logic [4:0] aluOp);
always_comb begin
aluOp = 'X;
unique case( col)
1: aluOp = OP_AND;
5: aluOp = OP_EXT;
default:
unique case( 1'b1)
row[1]:
unique case( col)
2: aluOp = OP_SUB;
3: aluOp = OP_SUBC;
4,6: aluOp = OP_SLAA;
endcase
row[2]:
unique case( col)
2: aluOp = OP_ADD;
3: aluOp = OP_ADDC;
4: aluOp = OP_ASR;
endcase
row[3]:
unique case( col)
2: aluOp = OP_ADDX;
3: aluOp = isCorf ? OP_ABCD : OP_ADD;
4: aluOp = OP_ASL;
endcase
row[4]:
aluOp = ( col == 4) ? OP_LSL : OP_AND;
row[5],
row[6]:
unique case( col)
2: aluOp = OP_SUB;
3: aluOp = OP_SUBC;
4: aluOp = OP_LSR;
endcase
row[7]: // MUL
unique case( col)
2: aluOp = OP_SUB;
3: aluOp = OP_ADD;
4: aluOp = OP_ROXR;
endcase
row[8]:
// OP_AND For EXT.L
// But would be more efficient to change ucode and use column 1 instead of col3 at ublock extr1!
unique case( col)
2: aluOp = OP_EXT;
3: aluOp = OP_AND;
4: aluOp = OP_ROXR;
endcase
row[9]:
unique case( col)
2: aluOp = OP_SUBX;
3: aluOp = OP_SBCD;
4: aluOp = OP_ROL;
endcase
row[10]:
unique case( col)
2: aluOp = OP_SUBX;
3: aluOp = OP_SUBC;
4: aluOp = OP_ROR;
endcase
row[11]:
unique case( col)
2: aluOp = OP_SUB0;
3: aluOp = OP_SUB0;
4: aluOp = OP_ROXL;
endcase
row[12]: aluOp = OP_ADDX;
row[13]: aluOp = OP_EOR;
row[14]: aluOp = (col == 4) ? OP_EOR : OP_OR;
row[15]: aluOp = (col == 3) ? OP_ADD : OP_OR; // OP_ADD used by DBcc
endcase
endcase
end
endmodule
// Decodes IRD into ALU row (1-15)
// Slow, but no need to optimize for speed since IRD is latched at least two CPU cycles before it is used
// We also register the result after combining with column from nanocode
//
// Many opcodes are not decoded because they either don't do any ALU op,
// or use only columns 1 and 5 that are the same for all rows.
module rowDecoder( input [15:0] ird,
output logic [15:0] row, output noCcrEn, output logic isArX);
// Addr or data register direct
wire eaRdir = (ird[ 5:4] == 2'b00);
// Addr register direct
wire eaAdir = (ird[ 5:3] == 3'b001);
wire size11 = ird[7] & ird[6];
always_comb begin
case( ird[15:12])
'h4,
'h9,
'hd:
isArX = row[10] | row[12];
default:
isArX = 1'b0;
endcase
end
always_comb begin
unique case( ird[15:12])
'h4: begin
if( ird[8])
row = `ALU_ROW_06; // chk (or lea)
else case( ird[11:9])
'b000: row = `ALU_ROW_10; // negx
'b001: row = `ALU_ROW_04; // clr
'b010: row = `ALU_ROW_05; // neg
'b011: row = `ALU_ROW_11; // not
'b100: row = (ird[7]) ? `ALU_ROW_08 : `ALU_ROW_09; // nbcd/swap/ext(or pea)
'b101: row = `ALU_ROW_15; // tst & tas
default: row = 0;
endcase
end
'h0: begin
if( ird[8]) // dynamic bit
row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13;
else case( ird[ 11:9])
'b000: row = `ALU_ROW_14; // ori
'b001: row = `ALU_ROW_04; // andi
'b010: row = `ALU_ROW_05; // subi
'b011: row = `ALU_ROW_02; // addi
'b100: row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13; // static bit
'b101: row = `ALU_ROW_13; // eori
'b110: row = `ALU_ROW_06; // cmpi
default: row = 0;
endcase
end
// MOVE
// move.b originally also rows 5 & 15. Only because IRD bit 14 is not decoded.
// It's the same for move the operations performed by MOVE.B
'h1,'h2,'h3: row = `ALU_ROW_02;
'h5:
if( size11)
row = `ALU_ROW_15; // As originally and easier to decode
else
row = ird[8] ? `ALU_ROW_05 : `ALU_ROW_02; // addq/subq
'h6: row = 0; //bcc/bra/bsr
'h7: row = `ALU_ROW_02; // moveq
'h8:
if( size11) // div
row = `ALU_ROW_01;
else if( ird[8] & eaRdir) // sbcd
row = `ALU_ROW_09;
else
row = `ALU_ROW_14; // or
'h9:
if( ird[8] & ~size11 & eaRdir)
row = `ALU_ROW_10; // subx
else
row = `ALU_ROW_05; // sub/suba
'hb:
if( ird[8] & ~size11 & ~eaAdir)
row = `ALU_ROW_13; // eor
else
row = `ALU_ROW_06; // cmp/cmpa/cmpm
'hc:
if( size11)
row = `ALU_ROW_07; // mul
else if( ird[8] & eaRdir) // abcd
row = `ALU_ROW_03;
else
row = `ALU_ROW_04; // and
'hd:
if( ird[8] & ~size11 & eaRdir)
row = `ALU_ROW_12; // addx
else
row = `ALU_ROW_02; // add/adda
'he:
begin
reg [1:0] stype;
if( size11) // memory shift/rotate
stype = ird[ 10:9];
else // register shift/rotate
stype = ird[ 4:3];
case( {stype, ird[8]})
0: row = `ALU_ROW_02; // ASR
1: row = `ALU_ROW_03; // ASL
2: row = `ALU_ROW_05; // LSR
3: row = `ALU_ROW_04; // LSL
4: row = `ALU_ROW_08; // ROXR
5: row = `ALU_ROW_11; // ROXL
6: row = `ALU_ROW_10; // ROR
7: row = `ALU_ROW_09; // ROL
endcase
end
default: row = 0;
endcase
end
// Decode opcodes that don't affect flags
// ADDA/SUBA ADDQ/SUBQ MOVEA
assign noCcrEn =
// ADDA/SUBA
( ird[15] & ~ird[13] & ird[12] & size11) |
// ADDQ/SUBQ to An
( (ird[15:12] == 4'h5) & eaAdir) |
// MOVEA
( (~ird[15] & ~ird[14] & ird[13]) & ird[8:6] == 3'b001);
endmodule
// Row/col CCR update table
module ccrTable(
input [2:0] col, input [15:0] row, input finish,
output logic [MASK_NBITS-1:0] ccrMask);
localparam
KNZ00 = 5'b01111, // ok coz operators clear them
KKZKK = 5'b00100,
KNZKK = 5'b01100,
KNZ10 = 5'b01111, // Used by OP_EXT on divison overflow
KNZ0C = 5'b01111, // Used by DIV. V should be 0, but it is ok:
// DIVU: ends with quotient - 0, so V & C always clear.
// DIVS: ends with 1i (AND), again, V & C always clear.
KNZVC = 5'b01111,
XNKVC = 5'b11011, // Used by BCD instructions. Don't modify Z at all at the binary operation. Only at the BCD correction cycle
CUPDALL = 5'b11111,
CUNUSED = 5'bxxxxx;
logic [MASK_NBITS-1:0] ccrMask1;
always_comb begin
unique case( col)
1: ccrMask = ccrMask1;
2,3:
unique case( 1'b1)
row[1]: ccrMask = KNZ0C; // DIV, used as 3n in col3
row[3], // ABCD
row[9]: // SBCD/NBCD
ccrMask = (col == 2) ? XNKVC : CUPDALL;
row[2],
row[5],
row[10], // SUBX/NEGX
row[12]: ccrMask = CUPDALL; // ADDX
row[6], // CMP
row[7], // MUL
row[11]: ccrMask = KNZVC; // NOT
row[4],
row[8], // Not used in col 3
row[13],
row[14]: ccrMask = KNZ00;
row[15]: ccrMask = 5'b0; // TAS/Scc, not used in col 3
// default: ccrMask = CUNUSED;
endcase
4:
unique case( row)
// 1: DIV, only n (4n & 6n)
// 14: BCLR 4n
// 6,12,13,15 // not used
`ALU_ROW_02,
`ALU_ROW_03, // ASL (originally ANZVA)
`ALU_ROW_04,
`ALU_ROW_05: ccrMask = CUPDALL; // Shifts (originally ANZ0A)
`ALU_ROW_07: ccrMask = KNZ00; // MUL (originally KNZ0A)
`ALU_ROW_09,
`ALU_ROW_10: ccrMask = KNZ00; // RO[lr] (originally KNZ0A)
`ALU_ROW_08, // ROXR (originally ANZ0A)
`ALU_ROW_11: ccrMask = CUPDALL; // ROXL (originally ANZ0A)
default: ccrMask = CUNUSED;
endcase
5: ccrMask = row[1] ? KNZ10 : 5'b0;
default: ccrMask = CUNUSED;
endcase
end
// Column 1 (AND)
always_comb begin
if( finish)
ccrMask1 = row[7] ? KNZ00 : KNZKK;
else
ccrMask1 = row[13] | row[14] ? KKZKK : KNZ00;
end
endmodule

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000000000001000000110011100000000000000101001000001
00100001000000011000010001001000000110100000000001000000011001001001
00000001100000000010100000001000000110000000001001000000001001001001
00100000000000011000010001000000000101000000000010000000100001010000
11000001000000000000000000001000000100010000000001000000000001010001
00100001000000011000010000000000000000000000000101000000000000010000
01000001011000000000100000000110010001000000001100000000110100011000
01000001011000000000100000000110010001000000001100000001100100011000
00100001000000011000010000000000000100000000000001000000000001010000
10100100001000011000001000010000101001110000000001000100110010100001
01000000000000000000000010000000010100000000001000110001000000000000
00100001000000011000000000110010100100011111010001100000000001000000
00100010000000011000000000000000100010000100000000010100000100000011
00000001011000000000000001000110000000000000000010000000000100000000
00000000000000000000000000001000000100000000000001000000000001010001
00000001100000000010100000001000000110000000001001010000001001001001
00101000000000001000010000000000000000000000000010000000000000000000
01100010000000011000010010000000010100000000001000110001000000000000
00000000000000000000000010010010100000000000000100110010000000000000
00100000000000011000010001001000000110000000001001010000001001001001
00000000000000000000001000000000100100000000000000110010000001011000
00010010000000000100100000001000000100000000000010000000000001010001
00100010000000011100000000000000000001100000000010001000100000000000
00010010000000000100000000000000010001100000000010000000000000000000
00000000000000000000000000011001100110100000010001000000011011010001
10100010110000000000000000000000100000010000010010000100000100000000
10000000000000000000000000001000000100010000000001000000000001000001
00100000000000011001000000011010000110000000001001000000001001001001
00010011000000000000101000010000001001000000010101000000100000110000
00000001000000000001010000000000000000000000000101100000000000010000
00100010000000011000001000001000100110000000000001000000000001010001
00000001000000000010100001010000001001000000010110000000100000110000
01000001000000000000000000000000000001101010001100000000110000000000
00110100000000000100000100000000000000000000000010000000000000000000
00000000000100100000100000000000010000000000000000000001000000011000
01110101000000000100100000100010000001100000000000000000110100001010
00100010000000011010000100000000100010000100000000010100000100000011
11000001000000000000000000001000000100010000000001000000000001010001
01010011000000000100100000100010000001100000000000000000110100001010
11000001000000000000000000001001100110110000000001000000011011000001
01001001110000000000001000001000001000000000000101000000000000100001
00000000000000000000100000100010010000000000000000110001000100000010
00010000110000000001010000000000000000011100000010000000000000011000
01010001110000000001000000011010100100000000000001000000000001000001
00000000000000000000000001000000000100000000001100010000000001010000
00001000000000011001001000001000000110100000000001000100000011010001
01010001110000000001010000001000001000000000000101000000000000110001
10100010110100100100000001000000000001110000000010000000110000010000
00000000000100000000000000000010100001001010000101100000100000010000
00010000110000000001000000000000100000000000010010000100000100000000
10000000000000000000000000001000000100010000000001000000000001000001
00000001000000000000000001000000001001000000000101000000100000100000
00010010000000000000100000001010101000000000000101000000000000110001
10100000000100111000000000100001100010111010000101100000011010010010
00100000000000011000000000110010100110000000010000100000001101000010
00010010000000001100000000000000000000000000000010000000000000000000
11000001000000000000001000011101100100010000000001000000000001000001
00010100000000000100000100000000000000000000000010000000000000000000
10100010110000000100001000000000100000010000010010000100000010000000
00100000000100111000000000000000100000010010000101000100000100010010
00100010000000011000000000000000100010000100000000010100000100000011
00100010100000011001010000010000100100000000001110000100001000000000
00000000000100000000000000000010100000001010000101000000000000010000
00100010100000011001000000010010100100000000001110000100001000000000
00000001000000000000010000000000100000000000010101000100000010010000
00000000000100100000000000100010000000000100000000110001000100011010
00100000000000011000000000010000100110000000011000100000001001000000
00000000000100100000100000100010010000000000000000110001000100011010
00000000011000000000000000000110000000000000001110000000110100111000
00011000000000011001001000001000000100000000000001000000000001010001
00100010000000011100000000000000000001100000000010001000100000000000
00110000100000001000000100000000100000000000000010000100000100000000
00000000000100000000000000000010100001000000000101100000100000010000
10100010110000000100001000010001100000010000000010000000000000000000
01000001000000000000000000000000000000000000000101000000000000010000
10000000000000000000000000001000000100010000000001000000000001000001
00000000000000000000000000001000001000000000000101000000000000110001
00001000110000000000001000000000000000000000000010000000000000000000
00010010000000001100000000000000000000000000000010000000000000000000
00010000000000001010000100000000110001000000000010000100011000000000
01010001000000011000001000000000000001100000000000000000110000000000
00001100000000011000001000100001000010100000000101110000000000000011
01000000000000000000000010000000010100000000001000110000000001000000
11000001000000000000000000001000001000010000000101000000000000100001
00000000000000000000000000001000000100011100000001100000000001000001
00000000000000000000000000000000000000000000000101100000000000000000
00000000000100000000000000000000100000000000000101000100000100010000
11101011000000000000000000000000000000010000000010000000000000000000
01100001000000011001000000011010100100000000000001000000000001000001
01100010000000011000010010000000010100000000001000110000000001000000
00000000000000000000000010010010100000000000010100110000000100000000
01000001000000000000010000011001101000000000000101000100001000110001
00100000000100111100000000000000000010000010000100100010001000010000
00010010000000000000000000000010110100000000001110000000000000011000
00000000000000000000001000010000100100000000011100110010000001011000
00000000000100000000000000010000111000000000010101000100011000110000
00000000011000000010100000000110000100000000001101110000000101000000
00000000000000000000000000000000000000000000000010000000000000000000
00000001000000000000000000000000010101001010001101000000100001010000
00000001000000000000010000000000100000000000000101000100001000010000
01110101000000010000001000000000000001100000000000000000110000000000
01000001000000000000000010000000010100001010001000110001000000000000
00100010000000011000000000011010101010000000010101000000001100110001
00100001000000011000010001010000000100000000010000010000000001010000
01000001000000000000010000000000100000000110000101000000000000010000
01000001000000000000000010000000010100001010001000110001000000000000
00100000000000011000010001010001000000000000011010000000000010001000
00000001000000000000000001010000000100000000010001110000000001000000
00010010000000001000000000011010101000000000000101000000000000110001
00000000000000000000000000001000001000000000000101000000000000110001
00010010000000000001100000000010000000000000000101100000000000000000
00010010000000000001000000000010000100000000000101100000000000000000
00100010000000011100000000001000001000000000000101000000000000100001
00000001000000000001010000000000001010100000000110000000011000101000
00000001100000000000100000000000000000000000000101000000000000010000
00010010000000000000101000001001000100000000001001000000000011010001
11110101001000000100000000000000000000010000000010000000000000000000
00000000000000000000010000001001101000000000000101000010000010110001
00000000000000000000010000000000100000000110000101100000000000000000
00100010100000001001100000000010000010000100001000000000001000001000
00100010100000001001000000000010000110000100001000000000001000001000
00010010000000001000010000000000000000000000001110000000000000011000
00110100000100101100000000000000000001100000000001100000110000010000
01110101000000001000000100000000111000000000010010000100000100000000
01000000000000000000010000010000100110000000011100100000000001011000
11010011000000000000101000001001000100010000001001000000000011010001
11110101001000000000000000000000100000010000000010000100000100000000
01110101000000000100000000000000010000000000010010001000000001000000
01110101000000000000000000000000110000000000010010001100000101000000
01110101000000000000000000000000110000000000010010001100011001000000
01110000000000011100000000000000000001100000001101000000110000000000
00010000000000001000000000000010100000000000000010000000000000000000
00010010000000000100000100000000010001000000000010000000000000000000
01000000000000000000010000010000100110000000011100100010001001011000
00100000000000011000010000000000000100000000000000100000000001000000
00000001000000000000000000000000001000000000000101000000000000110000
00100001000000011100000001011001000110000000011000000000001011001001
01100001000000011000000000010010100110000000011100100000001101011000
01100001000000011000010000010010000010000000010101000000001100010000
00000000000000000000000100000000010010100000001100110001011000011000
01100001000000011000000000010000100110000000011000100000001001000000
00000000000000000000000000001000000100011100000001100000000001000001
00010010000000000000000000010010110110000000001110000010001000011000
01000001000000000000100000010010010000000000010000110001000100011000
00010010000000000000010000010000110110000000001110000010001000011000
01000001000000000000000010000000010100001010001000110000000001000000
01000001000000000000010000001000101000000110000101000000000000110001
00000001000000000000010000000000100000000000000101000100001000010000
00101000000000001000010000000000000000000000000010000000000000000000
00100010000000011000000000000000100000000000000010000100011000000000
00100010001000011010000000000000100000000000000010000100000100000000
11010011001000000100000000010000011000010000000010000000000000000000
00010010000000000100000000000000010000000000010010001000000001000000
00001000000000011000001000000000000000000000000101110000000000000011
00100010110000000000010000001000001000000000000101000000000000110001
00100010000000011000000000000000100010100000000010000000000000000000
00100000000000011000000000110001100100011111011001100000000011000010
00100000000000011000000000001000100110000000001001010000001001000001
01000001000000000000000000010000000100000000011100100000000001011000
00000000100000000010100000000000000001000000000101000000100000010000
00000001000000000000000000011001000100000000011001000000000011000001
00000000011000000010100001000110000101000000000000010000100101010000
00100001000000011100000001011001000100000000011001000000000011000001
01000000000000000000000000000000000101001010001101100000100001000000
00000000000100000000000000000000100001001010000101100100100100010000
00000000011000000000000000000010110110000000001100000000001101011000
01000001000000000000000000000001111001100000001010000000110010100000
00110010000000011000000000010010100010000000001110000010001000011000
11000001000000000000000000011001100110110000010001000000011011000001
00100000000000011010000000100001110000001100001010000000000010000010
00000000000000000000000000010000000100010101010001100000000001000000
01000000000000000000000000000000000010100000000010000000011000001000
00000001000000000000000000000000000001101010001101000000110000010000
10000000000000000000001000001101100100010000000001000000000001000001
01110101000000000000000000000000110000000000000010001100000101000000
11000001000000000000000000001000000100010000000001000000000001000001
00100010000000011000000000001001101000000010000101000010000010110001
00100010000100011000000000010010100000000000000101000000000000010000
11100101000000011100000000001001000100010000001001000000000011010001
00100100000100111000000000000000100000000000010101100100000100010000
00100010000100011000000000011010100100000000000000000000000001011001
00100000000000001000001000000000100000000000000010000100000010000000
00100010000000011100001000001000100100000000000001000100001001010001
00010010000000000100000100000000010001000000000010000000000000000000
10000000000000000000001000011101000100010000000001000000000001000001
00011000000000011000001000000000100010000000000010000000000000000000
01000000000000000000000000000000000100000000000001000000000001010000
01000000000000000000010000010000100110000000011100100000011001001000
00000000001000000010001000010001010000000000000010001000000000100000
11100101000000011100000000001000001000010000000101000000000000110001
01000001000000000000001000010001100000000000000010000000000000000000
00110100000000000000000000000000110000000000000010001100000101000000
10000000000000000000001000001000100100010000010001000100000011000001
01110101000000000100001000000001110000000000010010001000000001000000
10000000000000000000001000001000100100010000000001000100000011000001
00110100000000000000000000000000110000000000010010001100000101000000
00110100000000000000000000000000110000000000010010001100011001000000
01000000000000000000000000010000000110100000011100100000011001001000
00000000000100000000000000010000111000000000010101000100000100110010
00000000000100000000000000100010100001100000000001000000110000011000
01000000000000000000000000010010000110000000010000100000001101001000
00000000000000000000000000001000000110000000001001000000001001001001
01000000000000000000010000000001100000000000000101000010000010010000
01000000000000000000000000001000000110000000001001010000001001000001
00000001000000000000000000000000000001101010001101000000110000000000
11100101000000011000000000010000111001110000010010000100110100100000
00000000000000000000000000011010101010000000000101000010001000110001
11000001000000000000001000001101100100010000000001000000000001000001
00000000000000000000000100000000010000000000000001100001000000000000
00000000000000000000000000001001100100000000001001000000000011010001
11000001000000000000010000010001100000010000010010000000011010000000
00000000000000000000000000000000000000010110000010000000000000000000
00000000000000000000000000000000000000001100000000000001000000000000
00100010000000011000000000000000100010100000000010000000000000000000
00001000000000011000001000000000000000000000000101110000000000000011
10000000000000000000000000000000000000010000000010000000000000000000
00000000000000000000010000000000100010000000000010000010001000000000
00101000000000001000001000000000000000000000000010000000000000000000
01010011000000000000100000000010100001100000001100000000110000011000
00000001000010000000000001000000000000000000000101000000000000010000
00100010000000011000010000001101101000000000000101000000000000110001
00000000000000000000100000010010010000000000010000110001000100000000
01000000000000000000000000010000000100000000011100100000000001000000
00000000000000000000000100010010010000000000010000110001000100000000
01000000000000000000100000000000010000000000000001000000110000010000
01010011000000001000010000000000000001100000001100000000110000011000
01000001000000000000010000001001101000000000000101000000000000110001
00100100000100011001000000000000100000000000010101000100000100010000
01100010000000011000100000010010110010000000001100000000110000011000
00011000000000011000001000000000000000000000000101110000000000000011
00000000000000000000000000001000000100000000000001000000000001010001
00010010000000000100000100000000010001000000000010000000000000000000
00001010000000011000001000000000000000000000000101110000000000000011
00010010000000000000000000000001110100000010001110000010000010011000
01100010000000011000100000010010110010000000001100000001000000011000
01000000000000000000100000000010010000000000001100110001000100011000
00100010000100011000000001011010100100000000000001000000000001011001
00000001000000000000010000000001100001001010000101000000100000010000
00000000000000000000010000000000100101000110001110000000100001011000
00000000000000000000100000010010010000000000010000110001000100011000
01010011000000000000100000000001100001100010001100000010110010011000
01100011000000011000000000010010100100000000011101110000000001011000
00000000000100000001000000010000100100000000011101000100000101010000
00100010000100011000000001010010100100000000011100010000000001010000
00000001000000000000010000000000100000000001000101000100000010010000
00000001000000000000010000000001100000001111000101000000000000010000
00000000000000000000000000010010100000000110010101100000000100000000
00000111000000000000010000010000111000001000010110000100001000100000
01000000000000000000100000000001110000000000001001000000110010010000
01001011000000011000001000000000000001100000000000000000110000000000
00000000000000000000010000000000100010000000000101000000000000010000
10100100000000011100000000001000000100010000000001000000000001000001
00010000000000000000000000010000100100000010000010000000000000000000
00000000000000000000000000001000000100000010000000110010000001000001
01000000000000000000000000001001100100000000001001010000000011000001
00000000000000000000000000001001100100000000001001010000000011000001
00100000000000011000000000010010100010000000010101000000001100010000
00000000000100000000000000000000101000000000000101000100011000110000
00000000000100100000100000010010010000000000010000110001000100011000
01000000000000000000010000010001100000000000010101000010000010010000
00100001000000011100010100000000110010000000001110001000100000011000
00000000000000000000001000000000100000000110000101000000000000000000
00000110000000000000000000000000000000001000000010000000000000000000
01000000000000000000010000000000100100001010001100110010000001000000
01000000000000000000000000000000000100001010001100000000000001000000
01100001000000011000000000000000100001100010000000000000110000000000
01000001000000000000010000000000100000000110000101010000000000010000
00101000000000001000010000001000101010000000000101100000000000100001
10000110000000000000000000001000001000001000000101100000000000100001
00000000000000000000000000001000000100000000000001000000000001010001
00100010000100111000100000000000110010100000000001000000110000010000
00100100000100111100000000001000000100000000000001000000000001011001
00100011000000011000010100000000010000000000001110001000100000011000
00000000000000000000000000011001100110100000010001000000011011010001
00000000000000000000000000000000000000000000000010000000000000000000
00000000000100100000010001001000100100000000000001000000011001001001
00100100001000111100001000000000100010000000000101000000000000010000
01000001000000000000000000010001100000000010000010000000000000000000
00100010000000011010000000000000110100000000011110001100100100011000
11100101000000011100000100000000001000010000010101000000011010000000
00010000000000000000100000000000100001100010001100000000110000000000
00100010000100111000010001001000000100000000000000000000000001011001
00010000000000000010000000000000100100000010001110000000000000011000
11100011000000011100001000010101100000010000000101000000000000000000
00100000000000011000000000110010100100011111010001100000000001000000
10000000000100000000000000001000100110110000000001000000000001011001
11000001000000000000000000001001000100010000001001000000000011010001
00100100000100111100000000000000000000000000000101100000000000010000
10000000000100100000000001001001000100010000001001000000000011001001
11000001000000000000000000000000000000010000000010000000000000000000
00110100001100100000000000000000100000000000000101100100000100010000
00000001000001000000000001000000000000000000000101000000000000010000
00000001000010000000010001000000100000000000000101000100000010010000
00100000000100111000000000010000101000010111010101000100000100110010
11100101000000011100000000000000000000010000000010000000000000000000
11100101000000011000000000000000100000010000010010000100000100000000
00000000000000000000000000001000001000000000000101000000000000110001
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000000000000000000000000000000010000000000000000000
00000001000000000000000000001000001001100000000001000000110000110001
00000001000001000000000001001000000100000000000001010000000001011001
00100000000000001000001000000000100000000000000010000100000010000000
11000001000000000000010000001001001000010000000101000000000000110001
00000000000110000000000001000000100000000000000101000100000100010000
00000000000101000000000001000000100000000000000101000100000100010000
00000000000010100000000001010000000100000000000101000000000000010000
00000000000101000000000001001010000100000000000001010000000001011001
11100101001000011100000000000000010000010000010010001000000000100000
00100000000000001000000000001000001000000000000110000000000000110001
00100000000000011000000000000000100000000100011100000101000100011000
00100000000000011000000000010000110100000000011100000101000100011000
01100011100000011000000100010010000000000000000101110000000000000011
01100010000000011000010100000000010000000000001100000001000000011000
10000000000100100000000001001000000100010000000001000000000001011001
01100010000000011000010100000010010000000000001100110001000100011000
01100011000000011000010000010000000100000000011101110000000001011000
00000000000000000000010000000000100000000110000101000000000000010000
00000000000000000000000000000000000000011100001110000000000000011000
10100000000000001000010000001000101000000110000101000000000000100001
00100000000000011000000000110001100100001111011001100000000011000010
00000001000000000000010000000001100001001010000101000010100010010000
00100010001000111000010000010000000100000000011101000000000001010000
00100100000100111100000000000000000000000000000101000000000000010000
00100010000100011000010001010000000100000000011100010000000001010000
01000001000000000000000100010000011000000000000010000000000000000000
00000000000000000000010000000000100010000000000101000010001000010000
00100000000100111000000000000000100000000010000100100000000000010000
00100010000000011000010000001000001000000000000101000000000000110001
00000001000000000000010000000000100000000000000101000100000010010000
00000000000000000000000000000000000000000000000010000000000000000000
00000000000000000000001000000000100100000000000000110010000001011000
00000000011000000000000000000010110110000000001100000000001101011000

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// DC removal filter
// input is unsigned
// output is signed
/* verilator tracing_off */
module jt49_dcrm(
input clk,
input cen,
input rst,
input [7:0] din,
output reg signed [7:0] dout
);
wire signed [7:0] ave0, ave1;
jt49_mave u_mave0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( {1'b0, din[7:1] } ),
.dout ( ave0 )
);
jt49_mave u_mave1(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( ave0 ),
.dout ( ave1 )
);
always @(posedge clk)
if( cen )
dout <= ({1'b0,din} - {ave1,1'b0})>>>1;
endmodule

View File

@@ -0,0 +1,64 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// DC removal filter
// input is unsigned
// output is signed
module jt49_dcrm2 #(parameter sw=8) (
input clk,
input cen,
input rst,
input [sw-1:0] din,
output signed [sw-1:0] dout
);
localparam DW=10; // width of the decimal portion
reg signed [sw+DW:0] integ, exact, error;
//reg signed [2*(9+DW)-1:0] mult;
// wire signed [sw+DW:0] plus1 = { {sw+DW{1'b0}},1'b1};
reg signed [sw:0] pre_dout;
// reg signed [sw+DW:0] dout_ext;
reg signed [sw:0] q;
always @(*) begin
exact = integ+error;
q = exact[sw+DW:DW];
pre_dout = { 1'b0, din } - q;
//dout_ext = { pre_dout, {DW{1'b0}} };
//mult = dout_ext;
end
assign dout = pre_dout[sw-1:0];
always @(posedge clk)
if( rst ) begin
integ <= {sw+DW+1{1'b0}};
error <= {sw+DW+1{1'b0}};
end else if( cen ) begin
/* verilator lint_off WIDTH */
integ <= integ + pre_dout; //mult[sw+DW*2:DW];
/* verilator lint_on WIDTH */
error <= exact-{q, {DW{1'b0}}};
end
endmodule

View File

@@ -0,0 +1,67 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// Delay stage
// use for long delays
module jt49_dly #(parameter DW=8, depth=10)(
input clk,
input cen,
input rst,
input [7:0] din,
output reg [7:0] dout,
output reg [7:0] pre_dout
);
reg [depth-1:0] rdpos, wrpos;
// memory
reg [DW-1:0] ram[0:2**depth-1];
always @(posedge clk)
if(rst)
pre_dout <= {DW{1'b0}};
else begin
pre_dout <= ram[rdpos];
if( cen ) ram[wrpos] <= din;
end
`ifdef SIMULATION
integer k;
initial begin
for(k=0;k<=2**depth-1;k=k+1)
ram[k] = 0;
end
`endif
always @(posedge clk)
if( rst ) begin
rdpos <= { {depth-1{1'b0}}, 1'b1};
wrpos <= {depth{1'b1}};
dout <= {DW{1'b0}};
end else if(cen) begin
dout <= pre_dout;
rdpos <= rdpos+1'b1;
wrpos <= wrpos+1'b1;
end
endmodule // jt49_dly

View File

@@ -0,0 +1,60 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// Moving averager
module jt49_mave #(parameter depth=8, DW=8)(
input clk,
input cen,
input rst,
input signed [DW-1:0] din,
output signed [DW-1:0] dout
);
wire [DW-1:0] dly0;
wire [DW-1:0] pre_dly0;
jt49_dly #(.depth(depth),.DW(DW)) u_dly0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
.din ( din ),
.dout ( dly0 ),
.pre_dout ( pre_dly0 )
);
// moving average
// D=2048
reg signed [DW:0] diff;
reg signed [DW+depth-1:0] sum;
always @(posedge clk)
if( rst ) begin
diff <= {DW+1{1'd0}};
sum <= {DW+depth+1{1'd0}};
end else if(cen) begin
diff <= {1'b0,din } - { 1'b0, dly0 };
sum <= { {depth{diff[DW]}}, diff } + sum;
end
assign dout = sum[DW+depth-1:depth];
endmodule

11
rtl/ipcores/jt49/jt49.qip Normal file
View File

@@ -0,0 +1,11 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_bus.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_cen.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_div.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_eg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_exp.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_noise.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path)/filter/jt49_dcrm.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path)/filter/jt49_dcrm2.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path)/filter/jt49_dly.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path)/filter/jt49_mave.v]

258
rtl/ipcores/jt49/jt49.v Normal file
View File

@@ -0,0 +1,258 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49 ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
input [3:0] addr,
input cs_n,
input wr_n, // write
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output reg [7:0] dout,
output reg [9:0] sound, // combined channel output
output reg [7:0] A, // linearised channel output
output reg [7:0] B,
output reg [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out,
output IOB_oe
);
parameter [2:0] COMP=3'b000;
parameter YM2203_LUMPED=0;
parameter CLKDIV=3;
wire [2:0] comp = COMP;
reg [7:0] regarray[15:0];
wire [7:0] port_A, port_B;
wire [4:0] envelope;
wire bitA, bitB, bitC;
wire noise;
reg Amix, Bmix, Cmix;
wire cen16, cen256;
assign IOA_out = regarray[14];
assign IOB_out = regarray[15];
assign port_A = IOA_in;
assign port_B = IOB_in;
assign IOA_oe = regarray[7][6];
assign IOB_oe = regarray[7][7];
assign sample = cen16;
jt49_cen #(.CLKDIV(CLKDIV)) u_cen(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( clk_en ),
.sel ( sel ),
.cen16 ( cen16 ),
.cen256 ( cen256 )
);
// internal modules operate at clk/16
jt49_div #(12) u_chA(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[1][3:0], regarray[0][7:0] } ),
.div ( bitA )
);
jt49_div #(12) u_chB(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[3][3:0], regarray[2][7:0] } ),
.div ( bitB )
);
jt49_div #(12) u_chC(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[5][3:0], regarray[4][7:0] } ),
.div ( bitC )
);
jt49_noise u_ng(
.clk ( clk ),
.cen ( cen16 ),
.rst_n ( rst_n ),
.period ( regarray[6][4:0] ),
.noise ( noise )
);
// envelope generator
wire eg_step;
wire [15:0] eg_period = {regarray[4'hc],regarray[4'hb]};
wire null_period = eg_period == 16'h0;
jt49_div #(16) u_envdiv(
.clk ( clk ),
.cen ( cen256 ),
.rst_n ( rst_n ),
.period ( eg_period ),
.div ( eg_step )
);
reg eg_restart;
jt49_eg u_env(
.clk ( clk ),
.cen ( cen256 ),
.step ( eg_step ),
.rst_n ( rst_n ),
.restart ( eg_restart ),
.null_period( null_period ),
.ctrl ( regarray[4'hD][3:0] ),
.env ( envelope )
);
reg [4:0] logA, logB, logC, log;
wire [7:0] lin;
jt49_exp u_exp(
.clk ( clk ),
.comp ( comp ),
.din ( log ),
.dout ( lin )
);
wire [4:0] volA = { regarray[ 8][3:0], regarray[ 8][3] };
wire [4:0] volB = { regarray[ 9][3:0], regarray[ 9][3] };
wire [4:0] volC = { regarray[10][3:0], regarray[10][3] };
wire use_envA = regarray[ 8][4];
wire use_envB = regarray[ 9][4];
wire use_envC = regarray[10][4];
wire use_noA = regarray[ 7][3];
wire use_noB = regarray[ 7][4];
wire use_noC = regarray[ 7][5];
reg [3:0] acc_st;
always @(posedge clk) if( clk_en ) begin
Amix <= (noise|use_noA) & (bitA|regarray[7][0]);
Bmix <= (noise|use_noB) & (bitB|regarray[7][1]);
Cmix <= (noise|use_noC) & (bitC|regarray[7][2]);
logA <= !Amix ? 5'd0 : (use_envA ? envelope : volA );
logB <= !Bmix ? 5'd0 : (use_envB ? envelope : volB );
logC <= !Cmix ? 5'd0 : (use_envC ? envelope : volC );
end
reg [9:0] acc;
wire [9:0] elin;
assign elin = {2'd0,lin};
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
acc_st <= 4'b1;
acc <= 10'd0;
A <= 8'd0;
B <= 8'd0;
C <= 8'd0;
sound <= 10'd0;
end else if(clk_en) begin
acc_st <= { acc_st[2:0], acc_st[3] };
// Lumping the channel outputs for YM2203 will cause only the higher
// voltage to pass throuh, as the outputs seem to use a source follower.
acc <= YM2203_LUMPED==1 ? (acc>elin ? acc : elin) : acc + elin;
case( acc_st )
4'b0001: begin
log <= logA;
acc <= 10'd0;
sound <= acc;
end
4'b0010: begin
A <= lin;
log <= logB;
end
4'b0100: begin
B <= lin;
log <= logC;
end
4'b1000: begin // last sum
C <= lin;
end
default:;
endcase
end
end
reg [7:0] read_mask;
always @(*)
case(addr)
4'h0,4'h2,4'h4,4'h7,4'hb,4'hc,4'he,4'hf:
read_mask = 8'hff;
4'h1,4'h3,4'h5,4'hd:
read_mask = 8'h0f;
4'h6,4'h8,4'h9,4'ha:
read_mask = 8'h1f;
endcase // addr
// register array
wire write;
reg last_write;
wire wr_edge = write & ~last_write;
assign write = !wr_n && !cs_n;
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
dout <= 8'd0;
last_write <= 0;
eg_restart <= 0;
regarray[0]<=8'd0; regarray[4]<=8'd0; regarray[ 8]<=8'd0; regarray[12]<=8'd0;
regarray[1]<=8'd0; regarray[5]<=8'd0; regarray[ 9]<=8'd0; regarray[13]<=8'd0;
regarray[2]<=8'd0; regarray[6]<=8'd0; regarray[10]<=8'd0; regarray[14]<=8'd0;
regarray[3]<=8'd0; regarray[7]<=8'd0; regarray[11]<=8'd0; regarray[15]<=8'd0;
end else begin
last_write <= write;
// Data read
case( addr )
4'he: dout <= port_A;
4'hf: dout <= port_B;
default: dout <= regarray[ addr ] & read_mask;
endcase
// Data write
if( write ) begin
regarray[addr] <= din;
if ( addr == 4'hD && wr_edge ) eg_restart <= 1;
end else begin
eg_restart <= 0;
end
end
end
endmodule

105
rtl/ipcores/jt49/jt49_bus.v Normal file
View File

@@ -0,0 +1,105 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 28-Jan-2019
Based on sqmusic, by the same author
*/
// This is a wrapper with the BDIR/BC1 pins
module jt49_bus ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en /* synthesis direct_enable = 1 */,
// bus control pins of original chip
input bdir,
input bc1,
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output [7:0] dout,
output [9:0] sound, // combined channel output
output [7:0] A, // linearised channel output
output [7:0] B,
output [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out,
output IOB_oe
);
parameter [2:0] COMP=3'b000;
reg wr_n, cs_n;
reg [3:0] addr;
reg addr_ok;
reg [7:0] din_latch;
always @(posedge clk)
if( !rst_n ) begin
wr_n <= 1'b1;
cs_n <= 1'b1;
addr <= 4'd0;
addr_ok <= 1'b1;
end else begin // I/O cannot use clk_en
// addr must be
case( {bdir,bc1} )
2'b00: { wr_n, cs_n } <= 2'b11;
2'b01: { wr_n, cs_n } <= addr_ok ? 2'b10 : 2'b11;
2'b10: begin
{ wr_n, cs_n } <= addr_ok ? 2'b00 : 2'b11;
din_latch <= din;
end
2'b11: begin
{ wr_n, cs_n } <= 2'b11;
addr <= din[3:0];
addr_ok <= din[7:4] == 4'd0;
end
endcase // {bdir,bc1}
end
jt49 #(.COMP(COMP)) u_jt49( // note that input ports are not multiplexed
.rst_n ( rst_n ),
.clk ( clk ), // signal on positive edge
.clk_en ( clk_en ), // clock enable on negative edge
.addr ( addr[3:0] ),
.cs_n ( cs_n ),
.wr_n ( wr_n ), // write
.din ( din_latch ),
.sel ( sel ), // if sel is low, the clock is divided by 2
.dout ( dout ),
.sound ( sound ), // combined channel output
.sample ( sample ),
.A ( A ), // linearised channel output
.B ( B ),
.C ( C ),
.IOA_in ( IOA_in ),
.IOA_out( IOA_out ),
.IOA_oe ( IOA_oe ),
.IOB_in ( IOB_in ),
.IOB_out( IOB_out ),
.IOB_oe ( IOB_oe )
);
endmodule // jt49_bus

View File

@@ -0,0 +1,55 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_cen(
input clk,
input rst_n,
input cen, // base clock enable signal
input sel, // when low, divide by 2 once more
output reg cen16,
output reg cen256
);
reg [9:0] cencnt;
parameter CLKDIV = 3; // use 3 for standalone JT49 or 2
localparam eg = CLKDIV; //8;
wire toggle16 = sel ? ~|cencnt[CLKDIV-1:0] : ~|cencnt[CLKDIV:0];
wire toggle256= sel ? ~|cencnt[eg-2:0] : ~|cencnt[eg-1:0];
always @(posedge clk, negedge rst_n) begin
if(!rst_n)
cencnt <= 10'd0;
else begin
if(cen) cencnt <= cencnt+10'd1;
end
end
always @(posedge clk) begin
cen16 <= cen & toggle16;
cen256 <= cen & toggle256;
end
endmodule // jt49_cen

View File

@@ -0,0 +1,52 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_div #(parameter W=12 )(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input rst_n,
input [W-1:0] period,
output reg div
);
reg [W-1:0]count;
wire [W-1:0] one = { {W-1{1'b0}}, 1'b1};
always @(posedge clk, negedge rst_n ) begin
if( !rst_n) begin
count <= one;
div <= 1'b0;
end
else if(cen) begin
if( count>=period ) begin
count <= one;
div <= ~div;
end
else
/*if( period!={W{1'b0}} )*/ count <= count + one ;
end
end
endmodule

View File

@@ -0,0 +1,88 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_eg(
(* direct_enable *) input cen,
input clk, // this is the divided down clock from the core
input step,
input null_period,
input rst_n,
input restart,
input [3:0] ctrl,
output reg [4:0]env
);
reg inv, stop;
reg [4:0] gain;
wire CONT = ctrl[3];
wire ATT = ctrl[2];
wire ALT = ctrl[1];
wire HOLD = ctrl[0];
wire will_hold = !CONT || HOLD;
always @(posedge clk)
if( cen ) env <= inv ? ~gain : gain;
reg last_step;
wire step_edge = (step && !last_step) || null_period;
wire will_invert = (!CONT&&ATT) || (CONT&&ALT);
reg rst_latch, rst_clr;
always @(posedge clk) begin
if( restart ) rst_latch <= 1;
else if(rst_clr ) rst_latch <= 0;
end
always @( posedge clk, negedge rst_n )
if( !rst_n) begin
gain <= 5'h1F;
inv <= 0;
stop <= 0;
rst_clr <= 0;
end
else if( cen ) begin
last_step <= step;
if( rst_latch ) begin
gain <= 5'h1F;
inv <= ATT;
stop <= 1'b0;
rst_clr <= 1;
end
else begin
rst_clr <= 0;
if (step_edge && !stop) begin
if( gain==5'h00 ) begin
if( will_hold )
stop <= 1'b1;
else
gain <= gain-5'b1;
if( will_invert ) inv<=~inv;
end
else gain <= gain-5'b1;
end
end
end
endmodule

205
rtl/ipcores/jt49/jt49_exp.v Normal file
View File

@@ -0,0 +1,205 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
// Compression vs dynamic range
// 0 -> 43.6dB
// 1 -> 29.1
// 2 -> 21.8
// 3 -> 13.4
module jt49_exp(
input clk,
input [2:0] comp, // compression
input [4:0] din,
output reg [7:0] dout
);
reg [7:0] lut[0:159];
always @(posedge clk)
dout <= lut[ {comp,din} ];
initial begin
lut[0] = 8'd0;
lut[1] = 8'd1;
lut[2] = 8'd1;
lut[3] = 8'd1;
lut[4] = 8'd2;
lut[5] = 8'd2;
lut[6] = 8'd3;
lut[7] = 8'd3;
lut[8] = 8'd4;
lut[9] = 8'd5;
lut[10] = 8'd6;
lut[11] = 8'd7;
lut[12] = 8'd9;
lut[13] = 8'd11;
lut[14] = 8'd13;
lut[15] = 8'd15;
lut[16] = 8'd18;
lut[17] = 8'd22;
lut[18] = 8'd26;
lut[19] = 8'd31;
lut[20] = 8'd37;
lut[21] = 8'd45;
lut[22] = 8'd53;
lut[23] = 8'd63;
lut[24] = 8'd75;
lut[25] = 8'd90;
lut[26] = 8'd107;
lut[27] = 8'd127;
lut[28] = 8'd151;
lut[29] = 8'd180;
lut[30] = 8'd214;
lut[31] = 8'd255;
lut[32] = 8'd0;
lut[33] = 8'd7;
lut[34] = 8'd8;
lut[35] = 8'd10;
lut[36] = 8'd11;
lut[37] = 8'd12;
lut[38] = 8'd14;
lut[39] = 8'd15;
lut[40] = 8'd17;
lut[41] = 8'd20;
lut[42] = 8'd22;
lut[43] = 8'd25;
lut[44] = 8'd28;
lut[45] = 8'd31;
lut[46] = 8'd35;
lut[47] = 8'd40;
lut[48] = 8'd45;
lut[49] = 8'd50;
lut[50] = 8'd56;
lut[51] = 8'd63;
lut[52] = 8'd71;
lut[53] = 8'd80;
lut[54] = 8'd90;
lut[55] = 8'd101;
lut[56] = 8'd113;
lut[57] = 8'd127;
lut[58] = 8'd143;
lut[59] = 8'd160;
lut[60] = 8'd180;
lut[61] = 8'd202;
lut[62] = 8'd227;
lut[63] = 8'd255;
lut[64] = 8'd0;
lut[65] = 8'd18;
lut[66] = 8'd20;
lut[67] = 8'd22;
lut[68] = 8'd24;
lut[69] = 8'd26;
lut[70] = 8'd29;
lut[71] = 8'd31;
lut[72] = 8'd34;
lut[73] = 8'd37;
lut[74] = 8'd41;
lut[75] = 8'd45;
lut[76] = 8'd49;
lut[77] = 8'd53;
lut[78] = 8'd58;
lut[79] = 8'd63;
lut[80] = 8'd69;
lut[81] = 8'd75;
lut[82] = 8'd82;
lut[83] = 8'd90;
lut[84] = 8'd98;
lut[85] = 8'd107;
lut[86] = 8'd116;
lut[87] = 8'd127;
lut[88] = 8'd139;
lut[89] = 8'd151;
lut[90] = 8'd165;
lut[91] = 8'd180;
lut[92] = 8'd196;
lut[93] = 8'd214;
lut[94] = 8'd233;
lut[95] = 8'd255;
lut[96] = 8'd0;
lut[97] = 8'd51;
lut[98] = 8'd54;
lut[99] = 8'd57;
lut[100] = 8'd60;
lut[101] = 8'd63;
lut[102] = 8'd67;
lut[103] = 8'd70;
lut[104] = 8'd74;
lut[105] = 8'd78;
lut[106] = 8'd83;
lut[107] = 8'd87;
lut[108] = 8'd92;
lut[109] = 8'd97;
lut[110] = 8'd103;
lut[111] = 8'd108;
lut[112] = 8'd114;
lut[113] = 8'd120;
lut[114] = 8'd127;
lut[115] = 8'd134;
lut[116] = 8'd141;
lut[117] = 8'd149;
lut[118] = 8'd157;
lut[119] = 8'd166;
lut[120] = 8'd175;
lut[121] = 8'd185;
lut[122] = 8'd195;
lut[123] = 8'd206;
lut[124] = 8'd217;
lut[125] = 8'd229;
lut[126] = 8'd241;
lut[127] = 8'd255;
lut[128] = 8'd0;
lut[129] = 8'd8;
lut[130] = 8'd10;
lut[131] = 8'd12;
lut[132] = 8'd16;
lut[133] = 8'd22;
lut[134] = 8'd29;
lut[135] = 8'd35;
lut[136] = 8'd44;
lut[137] = 8'd50;
lut[138] = 8'd56;
lut[139] = 8'd60;
lut[140] = 8'd64;
lut[141] = 8'd85;
lut[142] = 8'd97;
lut[143] = 8'd103;
lut[144] = 8'd108;
lut[145] = 8'd120;
lut[146] = 8'd127;
lut[147] = 8'd134;
lut[148] = 8'd141;
lut[149] = 8'd149;
lut[150] = 8'd157;
lut[151] = 8'd166;
lut[152] = 8'd175;
lut[153] = 8'd185;
lut[154] = 8'd195;
lut[155] = 8'd206;
lut[156] = 8'd217;
lut[157] = 8'd229;
lut[158] = 8'd241;
lut[159] = 8'd255;
end
endmodule

View File

@@ -0,0 +1,62 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_noise(
(* direct_enable *) input cen,
input clk,
input rst_n,
input [4:0] period,
output reg noise
);
reg [5:0]count;
reg [16:0]poly17;
wire poly17_zero = poly17==17'b0;
wire noise_en;
reg last_en;
wire noise_up = noise_en && !last_en;
always @(posedge clk ) if(cen) begin
noise <= ~poly17[0];
end
always @( posedge clk, negedge rst_n )
if( !rst_n )
poly17 <= 17'd0;
else if( cen ) begin
last_en <= noise_en;
if( noise_up )
poly17 <= { poly17[0] ^ poly17[3] ^ poly17_zero, poly17[16:1] };
end
jt49_div #(5) u_div(
.clk ( clk ),
.cen ( cen ),
.rst_n ( rst_n ),
.period ( period ),
.div ( noise_en )
);
endmodule

View File

@@ -0,0 +1,105 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-12-2020 */
// SDRAM access multiplexer, 2 -> 1
module jtframe_ram1_1slot #(parameter
SDRAMW = 22,
SLOT0_DW = 16,
SLOT0_AW = 8,
/* verilator lint_off WIDTH */
parameter [SDRAMW-1:0] SLOT1_OFFSET = 0,
/* verilator lint_on WIDTH */
parameter REF_FILE="sdram_bank3.hex"
)(
input rst,
input clk,
input [SLOT0_AW-1:0] slot0_addr,
output [SLOT0_DW-1:0] slot0_dout,
input [SLOT0_DW-1:0] slot0_din,
input [SDRAMW-1:0] slot0_offset,
input slot0_cs,
output slot0_ok,
input slot0_wen,
input [1:0] slot0_wrmask,
output hold_rst, // signals a busy state so the game is kept in reset
// SDRAM controller interface
input sdram_ack,
output reg sdram_rd,
output reg sdram_wr,
output [SDRAMW-1:0] sdram_addr,
input data_rdy,
input data_dst,
input [15:0] data_read,
output reg [15:0] data_write, // only 16-bit writes
output reg [ 1:0] sdram_wrmask // each bit is active low
);
wire req, req_rnw;
reg we;
always @(posedge clk, posedge rst) begin
if( rst ) begin
we <= 0;
sdram_rd <= 0;
sdram_wr <= 0;
sdram_wrmask <= 0;
end else begin
if( sdram_ack ) begin
sdram_rd <= 0;
sdram_wr <= 0;
end
if( !we || data_rdy ) begin
we <= 0;
// accept a new request
if( req ) begin
we <= 1;
data_write <= hold_rst ? 16'd0 : {(SLOT0_DW==8?2:1){slot0_din}};
sdram_wrmask<= slot0_wrmask;
sdram_rd <= req_rnw;
sdram_wr <= ~req_rnw;
end
end
end
end
jtframe_ram_rq #(.SDRAMW(SDRAMW),.AW(SLOT0_AW),.DW(SLOT0_DW)) u_slot0(
.rst ( rst ),
.clk ( clk ),
.addr ( slot0_addr ),
.addr_ok ( slot0_cs ),
.offset ( slot0_offset ),
.wrdata ( slot0_din ),
.wrin ( slot0_wen ),
.req_rnw ( req_rnw ),
.sdram_addr( sdram_addr ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot0_dout ),
.req ( req ),
.data_ok ( slot0_ok ),
.we ( we ),
.erase_bsy ( hold_rst )
);
endmodule

View File

@@ -0,0 +1,344 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 6-12-2019 */
// 9 slots for SDRAM read-only access
// slot 0 --> maximum priority
// slot 8 --> minimum priority
// Each slot can be used for 8, 16 or 32 bit access
// Small 4 byte cache used for each slot
module jtframe_rom #(parameter
SLOT0_DW = 8, SLOT1_DW = 8, SLOT2_DW = 8, SLOT3_DW = 8,
SLOT4_DW = 8, SLOT5_DW = 8, SLOT6_DW = 8, SLOT7_DW = 8, SLOT8_DW = 8,
SLOT0_AW = 8, SLOT1_AW = 8, SLOT2_AW = 8, SLOT3_AW = 8,
SLOT4_AW = 8, SLOT5_AW = 8, SLOT6_AW = 8, SLOT7_AW = 8, SLOT8_AW = 8,
parameter [21:0] SLOT0_OFFSET = 22'h0,
parameter [21:0] SLOT1_OFFSET = 22'h0,
parameter [21:0] SLOT2_OFFSET = 22'h0,
parameter [21:0] SLOT3_OFFSET = 22'h0,
parameter [21:0] SLOT4_OFFSET = 22'h0,
parameter [21:0] SLOT5_OFFSET = 22'h0,
parameter [21:0] SLOT6_OFFSET = 22'h0,
parameter [21:0] SLOT7_OFFSET = 22'h0,
parameter [21:0] SLOT8_OFFSET = 22'h0
// SLOT0_BRAM = 0,
// SLOT1_BRAM = 0
)(
input rst,
input clk,
input [SLOT0_AW-1:0] slot0_addr, // 32 kB
input [SLOT1_AW-1:0] slot1_addr, // 160 kB, addressed as 8-bit words
input [SLOT2_AW-1:0] slot2_addr, // 32 kB
input [SLOT3_AW-1:0] slot3_addr, // 64 kB
input [SLOT4_AW-1:0] slot4_addr, // 256 kB
input [SLOT5_AW-1:0] slot5_addr, // 256 kB (16-bit words)
input [SLOT6_AW-1:0] slot6_addr, // 64 kB
input [SLOT7_AW-1:0] slot7_addr, // 32 kB
input [SLOT8_AW-1:0] slot8_addr, // 32 kB
// output data
output [SLOT0_DW-1:0] slot0_dout,
output [SLOT1_DW-1:0] slot1_dout,
output [SLOT2_DW-1:0] slot2_dout,
output [SLOT3_DW-1:0] slot3_dout,
output [SLOT4_DW-1:0] slot4_dout,
output [SLOT5_DW-1:0] slot5_dout,
output [SLOT6_DW-1:0] slot6_dout,
output [SLOT7_DW-1:0] slot7_dout,
output [SLOT8_DW-1:0] slot8_dout,
input slot0_cs,
input slot1_cs,
input slot2_cs,
input slot3_cs,
input slot4_cs,
input slot5_cs,
input slot6_cs,
input slot7_cs,
input slot8_cs,
output slot0_ok,
output slot1_ok,
output slot2_ok,
output slot3_ok,
output slot4_ok,
output slot5_ok,
output slot6_ok,
output slot7_ok,
output slot8_ok,
// SDRAM controller interface
input sdram_ack,
output reg sdram_req,
output reg [21:0] sdram_addr,
input data_dst,
input data_rdy,
input [15:0] data_read,
// deprecated
input downloading
);
reg [ 3:0] rd_state_last;
wire [ 8:0] req, ok;
reg [ 8:0] data_sel;
wire [21:0] slot0_addr_req,
slot1_addr_req,
slot2_addr_req,
slot3_addr_req,
slot4_addr_req,
slot5_addr_req,
slot6_addr_req,
slot7_addr_req,
slot8_addr_req;
assign slot0_ok = ok[0];
assign slot1_ok = ok[1];
assign slot2_ok = ok[2];
assign slot3_ok = ok[3];
assign slot4_ok = ok[4];
assign slot5_ok = ok[5];
assign slot6_ok = ok[6];
assign slot7_ok = ok[7];
assign slot8_ok = ok[8];
wire [21:0] offset0 = SLOT0_OFFSET,
offset1 = SLOT1_OFFSET,
offset2 = SLOT2_OFFSET,
offset3 = SLOT3_OFFSET,
offset4 = SLOT4_OFFSET,
offset5 = SLOT5_OFFSET,
offset6 = SLOT6_OFFSET,
offset7 = SLOT7_OFFSET,
offset8 = SLOT8_OFFSET;
jtframe_romrq #(.AW(SLOT0_AW),.DW(SLOT0_DW)) u_slot0(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset0 ),
.addr ( slot0_addr ),
.addr_ok ( slot0_cs ),
.sdram_addr( slot0_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot0_dout ),
.req ( req[0] ),
.data_ok ( ok[0] ),
.we ( data_sel[0] )
);
jtframe_romrq #(.AW(SLOT1_AW),.DW(SLOT1_DW)) u_slot1(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset1 ),
.addr ( slot1_addr ),
.addr_ok ( slot1_cs ),
.sdram_addr( slot1_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot1_dout ),
.req ( req[1] ),
.data_ok ( ok[1] ),
.we ( data_sel[1] )
);
jtframe_romrq #(.AW(SLOT2_AW),.DW(SLOT2_DW)) u_slot2(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset2 ),
.addr ( slot2_addr ),
.addr_ok ( slot2_cs ),
.sdram_addr( slot2_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot2_dout ),
.req ( req[2] ),
.data_ok ( ok[2] ),
.we ( data_sel[2] )
);
jtframe_romrq #(.AW(SLOT3_AW),.DW(SLOT3_DW)) u_slot3(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset3 ),
.addr ( slot3_addr ),
.addr_ok ( slot3_cs ),
.sdram_addr( slot3_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot3_dout ),
.req ( req[3] ),
.data_ok ( ok[3] ),
.we ( data_sel[3] )
);
jtframe_romrq #(.AW(SLOT4_AW),.DW(SLOT4_DW)) u_slot4(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset4 ),
.addr ( slot4_addr ),
.addr_ok ( slot4_cs ),
.sdram_addr( slot4_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot4_dout ),
.req ( req[4] ),
.data_ok ( ok[4] ),
.we ( data_sel[4] )
);
jtframe_romrq #(.AW(SLOT5_AW),.DW(SLOT5_DW)) u_slot5(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset5 ),
.addr ( slot5_addr ),
.addr_ok ( slot5_cs ),
.sdram_addr( slot5_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot5_dout ),
.req ( req[5] ),
.data_ok ( ok[5] ),
.we ( data_sel[5] )
);
jtframe_romrq #(.AW(SLOT6_AW),.DW(SLOT6_DW)) u_slot6(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset6 ),
.addr ( slot6_addr ),
.addr_ok ( slot6_cs ),
.sdram_addr( slot6_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot6_dout ),
.req ( req[6] ),
.data_ok ( ok[6] ),
.we ( data_sel[6] )
);
jtframe_romrq #(.AW(SLOT7_AW),.DW(SLOT7_DW)) u_slot7(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset7 ),
.addr ( slot7_addr ),
.addr_ok ( slot7_cs ),
.sdram_addr( slot7_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot7_dout ),
.req ( req[7] ),
.data_ok ( ok[7] ),
.we ( data_sel[7] )
);
jtframe_romrq #(.AW(SLOT8_AW),.DW(SLOT8_DW)) u_slot8(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset8 ),
.addr ( slot8_addr ),
.addr_ok ( slot8_cs ),
.sdram_addr( slot8_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot8_dout ),
.req ( req[8] ),
.data_ok ( ok[8] ),
.we ( data_sel[8] )
);
wire [8:0] active = ~data_sel & req;
always @(posedge clk, posedge rst)
if( rst ) begin
sdram_addr <= 22'd0;
sdram_req <= 1'b0;
data_sel <= 9'd0;
end else begin
if( sdram_ack ) sdram_req <= 1'b0;
// accept a new request
if( data_sel==9'd0 || data_rdy ) begin
sdram_req <= |active;
data_sel <= 9'd0;
case( 1'b1 )
active[0]: begin
sdram_addr <= slot0_addr_req;
data_sel[0] <= 1'b1;
end
active[1]: begin
sdram_addr <= slot1_addr_req;
data_sel[1] <= 1'b1;
end
active[2]: begin
sdram_addr <= slot2_addr_req;
data_sel[2] <= 1'b1;
end
active[3]: begin
sdram_addr <= slot3_addr_req;
data_sel[3] <= 1'b1;
end
active[4]: begin
sdram_addr <= slot4_addr_req;
data_sel[4] <= 1'b1;
end
active[5]: begin
sdram_addr <= slot5_addr_req;
data_sel[5] <= 1'b1;
end
active[6]: begin
sdram_addr <= slot6_addr_req;
data_sel[6] <= 1'b1;
end
active[7]: begin
sdram_addr <= slot7_addr_req;
data_sel[7] <= 1'b1;
end
active[8]: begin
sdram_addr <= slot8_addr_req;
data_sel[8] <= 1'b1;
end
default: ;
endcase
end
end
endmodule // jtframe_rom

View File

@@ -0,0 +1,168 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 6-12-2019 */
// 2 slots for SDRAM read-only access
// slot 0 --> maximum priority
// slot 1 --> minimum priority
// Each slot can be used for 8, 16 or 32 bit access
// Small 4 byte cache used for each slot
module jtframe_rom_2slots #(parameter
SDRAMW = 22,
SLOT0_DW = 8, SLOT1_DW = 8,
SLOT0_AW = 8, SLOT1_AW = 8,
SLOT0_LATCH = 0,
SLOT1_LATCH = 0,
SLOT0_DOUBLE = 0,
SLOT1_DOUBLE = 0,
SLOT0_OKLATCH= 1,
SLOT1_OKLATCH= 1,
parameter [SDRAMW-1:0] SLOT0_OFFSET = 0,
parameter [SDRAMW-1:0] SLOT1_OFFSET = 0,
parameter REF_FILE="sdram_bank3.hex"
)(
input rst,
input clk,
input [SLOT0_AW-1:0] slot0_addr,
input [SLOT1_AW-1:0] slot1_addr,
// output data
output [SLOT0_DW-1:0] slot0_dout,
output [SLOT1_DW-1:0] slot1_dout,
input slot0_cs,
input slot1_cs,
output slot0_ok,
output slot1_ok,
// SDRAM controller interface
input sdram_ack,
output reg sdram_req,
output reg [SDRAMW-1:0] sdram_addr,
input data_dst,
input data_rdy,
input [15:0] data_read
);
reg [ 3:0] ready_cnt;
reg [ 3:0] rd_state_last;
wire [ 1:0] req, ok;
reg [ 1:0] slot_sel;
wire [SDRAMW-1:0] slot0_addr_req,
slot1_addr_req;
assign slot0_ok = ok[0];
assign slot1_ok = ok[1];
wire [SDRAMW-1:0] offset0 = SLOT0_OFFSET,
offset1 = SLOT1_OFFSET;
jtframe_romrq #(.SDRAMW(SDRAMW),.AW(SLOT0_AW),.DW(SLOT0_DW),
.LATCH(SLOT0_LATCH),.DOUBLE(SLOT0_DOUBLE),.OKLATCH(SLOT0_OKLATCH))
u_slot0(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset0 ),
.addr ( slot0_addr ),
.addr_ok ( slot0_cs ),
.sdram_addr( slot0_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot0_dout ),
.req ( req[0] ),
.data_ok ( ok[0] ),
.we ( slot_sel[0] )
);
jtframe_romrq #(.SDRAMW(SDRAMW),.AW(SLOT1_AW),.DW(SLOT1_DW),
.LATCH(SLOT1_LATCH),.DOUBLE(SLOT1_DOUBLE),.OKLATCH(SLOT1_OKLATCH))
u_slot1(
.rst ( rst ),
.clk ( clk ),
.clr ( 1'b0 ),
.offset ( offset1 ),
.addr ( slot1_addr ),
.addr_ok ( slot1_cs ),
.sdram_addr( slot1_addr_req ),
.din ( data_read ),
.din_ok ( data_rdy ),
.dst ( data_dst ),
.dout ( slot1_dout ),
.req ( req[1] ),
.data_ok ( ok[1] ),
.we ( slot_sel[1] )
);
wire [1:0] active = ~slot_sel & req;
always @(posedge clk, posedge rst)
if( rst ) begin
sdram_addr <= 0;
sdram_req <= 0;
slot_sel <= 0;
end else begin
if( sdram_ack ) sdram_req <= 0;
// accept a new request
if( slot_sel==0 || data_rdy ) begin
sdram_req <= |active;
slot_sel <= 2'd0;
if( active[0] ) begin
sdram_addr <= slot0_addr_req;
slot_sel[0] <= 1;
end else if( active[1] ) begin
sdram_addr <= slot1_addr_req;
slot_sel[1] <= 1;
end
end
end
`ifdef JTFRAME_SDRAM_CHECK
reg [15:0] mem[0:4*1024*1024];
initial begin
$readmemh( REF_FILE, mem );
end
always @( posedge clk ) begin
if( data_rdy ) begin
if( !slot_sel ) begin
$display("ERROR: SDRAM data received but it had not been requested at time %t - %m\n", $time);
$finish;
end else if( { mem[sdram_addr+1], mem[sdram_addr] } !== data_read ) begin
$display("ERROR: Wrong data read at time %t - %m", $time);
$display(" at address %X", sdram_addr );
$display(" expecting %X_%X - Read %X_%X\n",
mem[sdram_addr+1], mem[sdram_addr], data_read[31:16], data_read[15:0]);
$finish;
end
end
end
`endif
endmodule

View File

@@ -0,0 +1,37 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-12-2020 */
module jtframe_rom_sync(
input clk,
input rdy_in,
input ack_in,
output rdy_out,
output ack_out
);
reg last_rdy, last_ack;
assign rdy_out = rdy_in & last_rdy;
assign ack_out = ack_in & last_ack;
always @(posedge clk) begin
last_rdy <= rdy_in;
last_ack <= ack_in;
end
endmodule

View File

@@ -0,0 +1,271 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 28-2-2019 */
// The best use case is with addr_ok going down and up for each addr change
// but it works too with addr_ok permanently high as long as addr input is
// not changed until the data_ok signal is produced. If the requester cannot
// guarantee that, it should toggle addr_ok for each request
// LATCH LATENCY Timing Requirements
// 0 1 medium
// 1 2 easy
module jtframe_romrq #(parameter
SDRAMW = 22, // SDRAM width
AW = 18,
DW = 8,
OKLATCH = 1, // Set to 1 to latch the data_ok signal. This implies that
// data_ok will be high for one clock cycle after the input address
// has changed. The requesting module needs to take care of that
// If OKLATCH is zero, data_ok is combinational and it will go to
// zero as soon as the input address changes. This simplifies the
// requesting logic but it is more demanding for timing constraints
DOUBLE = 0,
LATCH = 0 // dout is latched
)(
input rst,
input clk,
input clr, // clears the cache
input [SDRAMW-1:0] offset,
// <-> SDRAM
input [15:0] din,
input din_ok,
input dst,
input we,
output reg req,
output [SDRAMW-1:0] sdram_addr,
// <-> Consumer
input [AW-1:0] addr,
input addr_ok, // signals that value in addr is valid
output data_ok, // strobe that signals that data is ready
output reg [DW-1:0] dout
);
reg [AW-1:0] addr_req;
reg [AW-1:0] cached_addr0, cached_addr1, addr_l;
reg [31:0] cached_data0, cached_data1;
reg [1:0] good;
reg hit0, hit1;
reg dend, double, cache_ok;
wire [AW-1:0] shifted;
assign sdram_addr = offset + { {SDRAMW-AW{1'b0}}, addr_req>>(DW==8)};
assign data_ok = OKLATCH ? cache_ok : addr_ok && ( hit0 || hit1 );
always @(*) begin
case(DW)
8: addr_req = {addr[AW-1:2],2'b0};
16: addr_req = {addr[AW-1:1],1'b0};
32: addr_req = addr;
endcase
// It is important to leave === for simulations, instead of ==
// It shouldn't have any implication for synthesis
hit0 = addr_req === cached_addr0 && good[0];
hit1 = addr_req === cached_addr1 && good[1];
req = (!(hit0 || hit1) && !we) && addr_ok;
end
// reg [1:0] ok_sr;
always @(posedge clk, posedge rst) begin
if( rst ) begin
good <= 'd0;
cached_data0 <= 'd0;
cached_data1 <= 'd0;
cached_addr0 <= 'd0;
cached_addr1 <= 'd0;
cache_ok <= 0;
dend <= 0;
double <= 0;
end else begin
if( clr ) good <= 0;
if( req ) addr_l <= addr_req;
if( we ) begin
if( dst | (double&~dend) ) begin
cached_data1 <= cached_data0;
cached_addr1 <= cached_addr0;
cached_data0[31:16] <= din;
if( double )
cached_addr0[1] <= ~cached_addr0[1];
else
cached_addr0 <= addr_l;
good <= { good[0], 1'b1 };
dend <= 1;
end
if( dend ) begin
cached_data0[31:16] <= din;
cached_data0[15: 0] <= cached_data0[31:16];
if( !LATCH[0] && !DOUBLE[0] ) cache_ok<= 1;
if( DOUBLE ) double <= ~double;
dend <= 0;
end
end
else begin
cache_ok <= addr_ok && ( hit0 || hit1 );
double <= 0;
end
end
end
// data_mux selects one of two cache registers
// but if we are getting fresh data, it selects directly the new data
// this saves one clock cycle at the expense of more LUTs
wire [31:0] data_mux = hit0 ? cached_data0 : cached_data1;
reg [DW-1:0] preout;
generate
if(DW==8) begin
always @(*)
case( addr[1:0] )
2'd0: preout = data_mux[ 7: 0];
2'd1: preout = data_mux[15: 8];
2'd2: preout = data_mux[23:16];
2'd3: preout = data_mux[31:24];
endcase
end else if(DW==16) begin
always @(*)
case( addr[0] )
1'd0: preout = data_mux[15:0];
1'd1: preout = data_mux[31:16];
endcase
end else always @(*) preout = data_mux;
endgenerate
generate
if( LATCH==0 ) begin : data_latch
always @(*) dout = preout;
end else begin : no_data_latch
always @(posedge clk) dout <= preout;
end
endgenerate
`ifdef JTFRAME_SDRAM_STATS
jtframe_romrq_stats u_stats(
.clk ( clk ),
.rst ( rst ),
.req ( req ),
.we ( we ),
.din_ok ( din_ok ),
.data_ok( data_ok )
);
`endif
`ifdef SIMULATION
`ifndef VERILATOR
`ifndef JTFRAME_SIM_ROMRQ_NOCHECK
reg [AW-1:0] last_addr;
reg waiting, last_req;
always @(posedge clk, posedge rst) begin
if( rst ) begin
waiting <= 0;
last_req <= 0;
end else begin
last_req <= req;
if( req && !last_req ) begin
if( waiting ) begin
$display("ERROR: %m new request without finishing the previous");
$finish;
end
last_addr <= addr;
waiting <= 1;
end
if( din_ok && we ) waiting <= 0;
if( waiting && !addr_ok ) begin
$display("ERROR: %m data request interrupted");
$finish;
end
if( addr != last_addr && addr_ok) begin
if( waiting ) begin
$display("ERROR: %m address changed at time %t",$time);
#40 $finish;
end else waiting <= !hit0 && !hit1;
end
end
end
`endif
`endif
`endif
endmodule // jtframe_romrq
`ifdef JTFRAME_SDRAM_STATS
////////////////////////////////////////////////////////////////
module jtframe_romrq_stats(
input clk,
input rst,
input req,
input we,
input din_ok,
input data_ok
);
// latency data
integer cur, longest, shortest, total, acc_cnt;
reg cnt_en, last_req, first;
always @(posedge clk, posedge rst) begin
if( rst ) begin
cur <= 0;
longest <= 0;
shortest <= 10000;
cnt_en <= 0;
last_req <= 0;
acc_cnt <= 0;
total <= 0;
first <= 1;
end else begin
last_req <= req;
if(req && !last_req) begin
cur <= 1;
cnt_en <= 1;
acc_cnt <= acc_cnt+1;
end
if( cnt_en ) begin
cur <= cur+1;
if( (we && din_ok) || data_ok ) begin
if( !first ) begin
if(cur>longest) longest <= cur;
if(cur<shortest) shortest <= cur;
total <= total + cur;
end
first <= 0;
cnt_en <= 0;
end
end
end
end
initial begin
forever begin
/* verilator lint_off STMTDLY */
#16_666_667;
/* verilator lint_on STMTDLY */
if( !first )
$display("Latency %m %2d - %2d - %2d",
shortest, total/acc_cnt, longest );
end
end
endmodule
`endif

View File

@@ -0,0 +1,10 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_sdram64.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_sdram64_bank.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_sdram64_init.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_sdram64_rfsh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_sdram64_latch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_ram1_1slot.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_rom_2slots.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_romrq.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_rom.v ]

View File

@@ -0,0 +1,603 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 29-4-2021 */
// SDRAM is set to burst=2 (64 bits)
module jtframe_sdram64 #(
parameter AW=22,
HF=0, // 1 for HF operation (idle cycles), 0 for LF operation
// HF operation starts at 66.6MHz (1/15ns)
SHIFTED =0,
BA0_LEN =32, // 1=16 bits, 2=32 bits, 4=64 bits
BA1_LEN =32,
BA2_LEN =32,
BA3_LEN =32,
PROG_LEN=64,
BA0_AUTOPRECH=0,
BA1_AUTOPRECH=0,
BA2_AUTOPRECH=0,
BA3_AUTOPRECH=0,
MISTER =1, // shorts dqm to address bus 12/11 signals
RFSHCNT=9, // 8192 every 64ms or 1 every 7.8us ~ 8.2 per line (15kHz)
BAPRIO =1 // Bank requests are handled with higher priority to bank 0
// and lower to to bank 3
)(
input rst,
input clk,
output init,
// requests
input [AW-1:0] ba0_addr,
input [AW-1:0] ba1_addr,
input [AW-1:0] ba2_addr,
input [AW-1:0] ba3_addr,
input [3:0] rd,
input [3:0] wr,
input [15:0] din,
input [ 1:0] din_m, // write mask
// programming
input prog_en,
input [AW-1:0] prog_addr,
input prog_rd,
input prog_wr,
input [15:0] prog_din,
input [ 1:0] prog_din_m,
input [ 1:0] prog_ba,
output reg prog_dst,
output reg prog_dok,
output reg prog_rdy,
output reg prog_ack,
input rfsh, // triggers a distributed cycle of RFSHCNT refresh commands
// This is meant to be the horizontal blanking of a 15kHz video
// signal. Using HB as rfsh signal also prevents having a bank
// active for longer than tRAS_max (120us)
output [3:0] ack,
output reg [3:0] dst,
output reg [3:0] dok,
output reg [3:0] rdy,
output reg [15:0] dout,
// SDRAM interface
// SDRAM_A[12:11] and SDRAM_DQML/H are controlled in a way
// that can be joined together thru an OR operation at a
// higher level. This makes it possible to short the pins
// of the SDRAM, as done in the MiSTer 128MB module
inout [15:0] sdram_dq, // SDRAM Data bus 16 Bits
`ifdef VERILATOR // sdram_dq is used as input-only in Verilator sims
output [15:0] sdram_din, // Data to be stored in SDRAM
`endif
output reg [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 reg [ 1:0] sdram_ba, // SDRAM Bank Address
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 sdram_cke // SDRAM Chip Select
);
localparam BURSTLEN=(BA0_LEN>32 || BA1_LEN>32 ||BA2_LEN>32 ||BA3_LEN>32) ? 64 :(
(BA0_LEN>16 || BA1_LEN>16 ||BA2_LEN>16 ||BA3_LEN>16) ? 32 : 16);
localparam LATCH = HF==1;
// /CS /RAS /CAS /WE
localparam CMD_LOAD_MODE = 4'b0___0____0____0, // 0
CMD_REFRESH = 4'b0___0____0____1, // 1
CMD_PRECHARGE = 4'b0___0____1____0, // 2
CMD_ACTIVE = 4'b0___0____1____1, // 3
CMD_WRITE = 4'b0___1____0____0, // 4
CMD_READ = 4'b0___1____0____1, // 5
CMD_STOP = 4'b0___1____1____0, // 6 Burst terminate
CMD_NOP = 4'b0___1____1____1, // 7
CMD_INHIBIT = 4'b1___0____0____0; // 8
wire [3:0] br, bx0_cmd, bx1_cmd, bx2_cmd, bx3_cmd, rfsh_cmd,
ba_dst, ba_dbusy, ba_dbusy64, ba_rdy, ba_dok,
init_cmd, post_act, next_cmd, dqm_busy, match;
wire all_act, rfshing, rfsh_br, noreq, help;
reg all_dbusy, all_dbusy64;
reg [3:0] bg, cmd;
reg [14:0] prio_lfsr;
wire [12:0] bx0_a, bx1_a, bx2_a, bx3_a, init_a, next_a, rfsh_a,
ba0_row, ba1_row, ba2_row, ba3_row;
wire [ 1:0] next_ba, prio;
wire [AW-1:0] ba0_addr_l, ba1_addr_l, ba2_addr_l, ba3_addr_l;
wire [3:0] rd_l, wr_l;
wire [4:0] wr_busy, idle;
wire wr_cycle;
// prog signals
wire pre_dst, pre_dok, pre_ack, pre_rdy;
wire [12:0] pre_a;
wire [ 3:0] pre_cmd;
reg prog_rst, prog_bg, other_rst, rfsh_rst;
reg rfsh_bg;
reg [ 1:0] dqm;
wire [ 1:0] mask_mux;
wire all_dqm, prog_busy, pre_br;
assign {sdram_ncs, sdram_nras, sdram_ncas, sdram_nwe } = cmd;
assign {sdram_dqmh, sdram_dqml} = MISTER ? sdram_a[12:11] : dqm;
assign sdram_cke = 1;
assign all_act = |post_act;
assign all_dqm = |dqm_busy;
assign wr_cycle = |wr_busy;
assign {next_ba, next_cmd, next_a } =
init ? { 2'd0, init_cmd, init_a } : (
rfshing? { 2'd0, rfsh_cmd, rfsh_a } : (
prog_en? { prog_ba, pre_cmd, pre_a} : (
bg[3] ? { 2'd3, bx3_cmd, bx3_a } : (
bg[2] ? { 2'd2, bx2_cmd, bx2_a } : (
bg[1] ? { 2'd1, bx1_cmd, bx1_a } :
{ 2'd0, bx0_cmd, bx0_a } )))));
assign prio = prio_lfsr[1:0];
assign mask_mux = prog_en ? prog_din_m : din_m;
`ifndef VERILATOR
reg [15:0] dq_pad;
assign sdram_dq = dq_pad;
`else
assign sdram_din = prog_en ? prog_din : din;
`endif
always @(negedge clk) begin
prog_rst <= ~prog_en | init | rst;
rfsh_rst <= init | rst;
other_rst <= prog_en | init | rst;
end
always @(posedge clk) begin
dst <= ba_dst;
rdy <= ba_rdy;
all_dbusy <= |ba_dbusy;
all_dbusy64 <= |ba_dbusy64;
dok <= ba_dok;
dout <= sdram_dq;
cmd <= next_cmd;
// prog signals
prog_dst <= pre_dst;
prog_dok <= pre_dok;
prog_rdy <= pre_rdy;
prog_ack <= pre_ack;
sdram_ba <= next_ba;
sdram_a[10:0] <= next_a[10:0];
`ifndef VERILATOR
dq_pad <= wr_cycle ? (prog_en ? prog_din : din) : 16'hzzzz;
`endif
if( MISTER ) begin
if( next_cmd==CMD_ACTIVE )
sdram_a[12:11] <= next_a[12:11];
else
sdram_a[12:11] <= wr_cycle ? mask_mux : 2'd0;
end else begin
sdram_a[12:11] <= next_a[12:11];
dqm <= wr_cycle ? mask_mux : 2'd0;
end
end
always @(posedge clk, posedge rst) begin
if( rst ) begin
prio_lfsr <= 1;
end else begin
prio_lfsr <= { prio_lfsr[0]^prio_lfsr[14], prio_lfsr[14:1] };
end
end
jtframe_sdram64_latch #(.LATCH(LATCH),.AW(AW)) u_latch(
.rst ( rst ),
.clk ( clk ),
.ba0_addr ( ba0_addr ),
.ba1_addr ( ba1_addr ),
.ba2_addr ( ba2_addr ),
.ba3_addr ( ba3_addr ),
.ba0_addr_l ( ba0_addr_l),
.ba1_addr_l ( ba1_addr_l),
.ba2_addr_l ( ba2_addr_l),
.ba3_addr_l ( ba3_addr_l),
.ba0_row ( ba0_row ),
.ba1_row ( ba1_row ),
.ba2_row ( ba2_row ),
.ba3_row ( ba3_row ),
.match ( match ),
.prog_en ( prog_en ),
.prog_rd ( prog_rd ),
.prog_wr ( prog_wr ),
.rd ( rd ),
.rd_l ( rd_l ),
.wr ( wr ),
.wr_l ( wr_l ),
.noreq ( noreq )
);
jtframe_sdram64_init #(.HF(HF),.BURSTLEN(BURSTLEN)) u_init(
.rst ( rst ),
.clk ( clk ),
.init ( init ),
.cmd ( init_cmd ),
.sdram_a ( init_a )
);
jtframe_sdram64_rfsh #(.HF(HF),.RFSHCNT(RFSHCNT)) u_rfsh(
.rst ( rfsh_rst ),
.clk ( clk ),
.start ( rfsh ),
.br ( rfsh_br ),
.bg ( rfsh_bg ),
.noreq ( noreq ),
.rfshing ( rfshing ),
.cmd ( rfsh_cmd ),
.help ( help ),
.sdram_a ( rfsh_a )
);
jtframe_sdram64_bank #(
.AW ( AW ),
.HF ( HF ),
.SHIFTED ( SHIFTED ),
.BALEN ( PROG_LEN),
.BURSTLEN ( BURSTLEN),
// The programmer always precharges all banks
// at the beginning of the operation
.AUTOPRECH ( 1 ),
.PRECHARGE_ALL( 1 )
) u_prog(
.rst ( prog_rst ),
.clk ( clk ),
// requests
.addr ( prog_addr ),
.rd ( prog_rd ),
.wr ( prog_wr ),
.ack ( pre_ack ),
.dst ( pre_dst ), // data starts
.dbusy ( ), // prog works alone
.all_dbusy ( 1'd0 ),
.idle ( idle[4] ),
.dbusy64 ( prog_busy ),
.all_dbusy64( 1'd0 ),
.post_act ( ),
.all_act ( 1'd0 ),
.dqm_busy ( ),
.all_dqm ( 1'd0 ),
.wr_busy ( wr_busy[4] ),
.row ( ),
.match ( 1'b0 ),
.dok ( pre_dok ),
.rdy ( pre_rdy ),
.set_prech ( 1'd0 ),
// SDRAM interface
.br ( pre_br ), // bus request
.bg ( prog_bg ), // bus grant
.sdram_a ( pre_a ),
.cmd ( pre_cmd )
);
jtframe_sdram64_bank #(
.AW ( AW ),
.HF ( HF ),
.SHIFTED ( SHIFTED ),
.BURSTLEN ( BURSTLEN ),
.BALEN ( BA0_LEN ),
.AUTOPRECH( BA0_AUTOPRECH )
) u_bank0(
.rst ( other_rst ),
.clk ( clk ),
// requests
.addr ( ba0_addr_l ),
.rd ( rd_l[0] ),
.wr ( wr_l[0] ),
.ack ( ack[0] ),
.dst ( ba_dst[0] ), // data starts
.dbusy ( ba_dbusy[0]),
.all_dbusy ( all_dbusy ),
.idle ( idle[0] ),
.dbusy64 (ba_dbusy64[0]),
.all_dbusy64( all_dbusy64),
.wr_busy ( wr_busy[0] ),
.post_act ( post_act[0]),
.all_act ( all_act ),
.dqm_busy ( dqm_busy[0]),
.all_dqm ( all_dqm ),
.dok ( ba_dok[0] ),
.rdy ( ba_rdy[0] ),
.set_prech ( rfsh_bg ),
.row ( ba0_row ),
.match ( match[0] ),
// SDRAM interface
.br ( br[0] ), // bus request
.bg ( bg[0] ), // bus grant
.sdram_a ( bx0_a ),
.cmd ( bx0_cmd )
);
jtframe_sdram64_bank #(
.AW ( AW ),
.HF ( HF ),
.SHIFTED ( SHIFTED ),
.BURSTLEN ( BURSTLEN ),
.BALEN ( BA1_LEN ),
.AUTOPRECH( BA1_AUTOPRECH )
) u_bank1(
.rst ( other_rst ),
.clk ( clk ),
// requests
.addr ( ba1_addr_l ),
.rd ( rd_l[1] ),
.wr ( wr_l[1] ),
.ack ( ack[1] ),
.dst ( ba_dst[1] ), // data starts
.dbusy ( ba_dbusy[1]),
.all_dbusy ( all_dbusy ),
.idle ( idle[1] ),
.dbusy64 (ba_dbusy64[1]),
.all_dbusy64( all_dbusy64),
.wr_busy ( wr_busy[1] ),
.post_act ( post_act[1]),
.all_act ( all_act ),
.dok ( ba_dok[1] ),
.rdy ( ba_rdy[1] ),
.set_prech ( rfsh_bg ),
.dqm_busy ( dqm_busy[1]),
.all_dqm ( all_dqm ),
.row ( ba1_row ),
.match ( match[1] ),
// SDRAM interface
.br ( br[1] ), // bus request
.bg ( bg[1] ), // bus grant
.sdram_a ( bx1_a ),
.cmd ( bx1_cmd )
);
jtframe_sdram64_bank #(
.AW ( AW ),
.HF ( HF ),
.SHIFTED ( SHIFTED ),
.BURSTLEN ( BURSTLEN ),
.BALEN ( BA2_LEN ),
.AUTOPRECH( BA2_AUTOPRECH )
) u_bank2(
.rst ( other_rst ),
.clk ( clk ),
// requests
.addr ( ba2_addr_l ),
.rd ( rd_l[2] ),
.wr ( wr_l[2] ),
.ack ( ack[2] ),
.dst ( ba_dst[2] ), // data starts
.dbusy ( ba_dbusy[2]),
.all_dbusy ( all_dbusy ),
.idle ( idle[2] ),
.dbusy64 (ba_dbusy64[2]),
.all_dbusy64( all_dbusy64),
.wr_busy ( wr_busy[2] ),
.post_act ( post_act[2]),
.all_act ( all_act ),
.dok ( ba_dok[2] ),
.rdy ( ba_rdy[2] ),
.set_prech ( rfsh_bg ),
.dqm_busy ( dqm_busy[2]),
.all_dqm ( all_dqm ),
.row ( ba2_row ),
.match ( match[2] ),
// SDRAM interface
.br ( br[2] ), // bus request
.bg ( bg[2] ), // bus grant
.sdram_a ( bx2_a ),
.cmd ( bx2_cmd )
);
jtframe_sdram64_bank #(
.AW ( AW ),
.HF ( HF ),
.SHIFTED ( SHIFTED ),
.BURSTLEN ( BURSTLEN ),
.BALEN ( BA3_LEN ),
.AUTOPRECH( BA3_AUTOPRECH )
) u_bank3(
.rst ( other_rst ),
.clk ( clk ),
// requests
.addr ( ba3_addr_l ),
.rd ( rd_l[3] ),
.wr ( wr_l[3] ),
.ack ( ack[3] ),
.dst ( ba_dst[3] ), // data starts
.dbusy ( ba_dbusy[3]),
.all_dbusy ( all_dbusy ),
.wr_busy ( wr_busy[3] ),
.idle ( idle[3] ),
.dbusy64 (ba_dbusy64[3]),
.all_dbusy64( all_dbusy64),
.post_act ( post_act[3]),
.all_act ( all_act ),
.dok ( ba_dok[3] ),
.rdy ( ba_rdy[3] ),
.set_prech ( rfsh_bg ),
.dqm_busy ( dqm_busy[3]),
.all_dqm ( all_dqm ),
.row ( ba3_row ),
.match ( match[3] ),
// SDRAM interface
.br ( br[3] ), // bus request
.bg ( bg[3] ), // bus grant
.sdram_a ( bx3_a ),
.cmd ( bx3_cmd )
);
always @(*) begin
rfsh_bg = &idle && (noreq | help) && rfsh_br;
prog_bg = pre_br & !rfshing;
if( rfshing | help ) begin
bg=0;
end else begin
if( BAPRIO ) begin
casez( br ) // Bank requests have priority (eases timing)
4'b???1: bg=4'b0001;
4'b??10: bg=4'b0010;
4'b?100: bg=4'b0100;
4'b1000: bg=4'b1000;
default: bg=0;
endcase
end else begin // Bank requests are randomized (tougher timing)
case( {br, prio[1:0]} )
6'b0000_00: bg=4'b0000;
6'b0000_01: bg=4'b0000;
6'b0000_10: bg=4'b0000;
6'b0000_11: bg=4'b0000;
6'b0001_00: bg=4'b0001;
6'b0001_01: bg=4'b0001;
6'b0001_10: bg=4'b0001;
6'b0001_11: bg=4'b0001;
6'b0010_00: bg=4'b0010;
6'b0010_01: bg=4'b0010;
6'b0010_10: bg=4'b0010;
6'b0010_11: bg=4'b0010;
6'b0011_00: bg=4'b0001;
6'b0011_01: bg=4'b0010;
6'b0011_10: bg=4'b0001;
6'b0011_11: bg=4'b0010;
6'b0100_00: bg=4'b0100;
6'b0100_01: bg=4'b0100;
6'b0100_10: bg=4'b0100;
6'b0100_11: bg=4'b0100;
6'b0101_00: bg=4'b0001;
6'b0101_01: bg=4'b0001;
6'b0101_10: bg=4'b0100;
6'b0101_11: bg=4'b0100;
6'b0110_00: bg=4'b0010;
6'b0110_01: bg=4'b0010;
6'b0110_10: bg=4'b0100;
6'b0110_11: bg=4'b0100;
6'b0111_00: bg=4'b0001;
6'b0111_01: bg=4'b0010;
6'b0111_10: bg=4'b0100;
6'b0111_11: bg=4'b0001; //*0001
6'b1000_00: bg=4'b1000;
6'b1000_01: bg=4'b1000;
6'b1000_10: bg=4'b1000;
6'b1000_11: bg=4'b1000;
6'b1001_00: bg=4'b0001;
6'b1001_01: bg=4'b0001;
6'b1001_10: bg=4'b1000;
6'b1001_11: bg=4'b1000;
6'b1010_00: bg=4'b0010;
6'b1010_01: bg=4'b0010;
6'b1010_10: bg=4'b1000;
6'b1010_11: bg=4'b1000;
6'b1011_00: bg=4'b0001;
6'b1011_01: bg=4'b0010; //*0010
6'b1011_10: bg=4'b0010;
6'b1011_11: bg=4'b1000;
6'b1100_00: bg=4'b1000;
6'b1100_01: bg=4'b0100;
6'b1100_10: bg=4'b0100;
6'b1100_11: bg=4'b1000;
6'b1101_00: bg=4'b0001;
6'b1101_01: bg=4'b0100; //*0100
6'b1101_10: bg=4'b0100;
6'b1101_11: bg=4'b1000;
6'b1110_00: bg=4'b1000; //*1000
6'b1110_01: bg=4'b0010;
6'b1110_10: bg=4'b0100;
6'b1110_11: bg=4'b1000;
6'b1111_00: bg=4'b0001;
6'b1111_01: bg=4'b0010;
6'b1111_10: bg=4'b0100;
6'b1111_11: bg=4'b1000;
endcase
end
end
end
`ifdef SIMULATION
always @(posedge clk) begin
if( (rd!=0 || wr!=0) && init ) begin
$display("\nERROR: SDRAM rd/wr inputs should be zero during initialization (%m)");
$finish;
end
end
`endif
endmodule

View File

@@ -0,0 +1,256 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 29-4-2021 */
// SDRAM is set to burst=2 (64 bits)
module jtframe_sdram64_bank #(
parameter AW=22,
HF=0, // 1 for HF operation (idle cycles), 0 for LF operation
// HF operation starts at 66.6MHz (1/15ns)
SHIFTED =0,
AUTOPRECH =0,
PRECHARGE_ALL=0,
BALEN =64, // 16, 32 or 64 bits
BURSTLEN =64,
READONLY =1 // set to 1 if ALL BANKS can only read
// this will make dbusy64 match dbusy
)(
input rst,
input clk,
// requests
input [AW-1:0] addr,
input rd,
input wr,
output ack,
output dst, // data starts
output reg dok, // data ok
output rdy,
input set_prech,
output dbusy, // DQ bus busy (read values only)
output dbusy64, // DQ bus busy (the full four clock cycles)
output reg dqm_busy, // DQM lines are used
output reg wr_busy, // output access to DQ bus
input all_dbusy,
input all_dbusy64,
input all_dqm,
output idle,
output reg post_act, // cycles banned for activate (tRRD)
input all_act,
// row matching
output reg [12:0] row,
input match,
// SDRAM interface
output reg br, // bus request
input bg, // bus grant
// SDRAM_A[12:11] and SDRAM_DQML/H are controlled in a way
// that can be joined together thru an OR operation at a
// higher level. This makes it possible to short the pins
// of the SDRAM, as done in the MiSTer 128MB module
output reg [12:0] sdram_a, // SDRAM Address bus 13 Bits
output reg [ 3:0] cmd
);
localparam ROW=13,
COW= AW==22 ? 9 : 10; // 9 for 32MB SDRAM, 10 for 64MB
// states
localparam IDLE = 0,
// AUTOPRECH 1+2(1)
PRE_ACT = HF ? 3:2,
ACT = PRE_ACT+1,
PRE_RD = PRE_ACT + (HF ? 3:2),
READ = PRE_RD+1,
DST = READ + (SHIFTED ? 1 : 2) ,
DTICKS = BURSTLEN==64 ? 4 : (BURSTLEN==32?2:1),
BUSY = DST+(DTICKS-1),
RDY = DST + (BALEN==16 ? 0 : (BALEN==32? 1 : 3)),
STW = BUSY + 2 + {2'd0,AUTOPRECH[0]};
// /CS /RAS /CAS /WE
localparam CMD_LOAD_MODE = 4'b0___0____0____0, // 0
CMD_REFRESH = 4'b0___0____0____1, // 1
CMD_PRECHARGE = 4'b0___0____1____0, // 2
CMD_ACTIVE = 4'b0___0____1____1, // 3
CMD_WRITE = 4'b0___1____0____0, // 4
CMD_READ = 4'b0___1____0____1, // 5
CMD_STOP = 4'b0___1____1____0, // 6 Burst terminate
CMD_NOP = 4'b0___1____1____1, // 7
CMD_INHIBIT = 4'b1___0____0____0; // 8
localparam [STW-1:0] ONE = 1;
/*
`ifdef SIMULATION
initial begin
$display("%m\n\tREAD=%2d\n\tDST=%2d\n\tRDY=%2d\n\tSTW=%2d",READ,DST,RDY,STW);
end
`endif
*/
reg actd, prechd;
wire [ROW-1:0] addr_row;
reg [STW-1:0] st, next_st, rot_st;
reg last_act;
wire rd_wr;
reg do_prech, do_act, do_read, written;
// state phases
reg in_busy, in_busy64;
// SDRAM pins
assign ack = st[READ],
dst = st[DST] | (st[READ] & wr),
dbusy = |{in_busy, do_read},
dbusy64 = READONLY ? dbusy : |{in_busy64, do_read},
rdy = (written && !AUTOPRECH) ? st[READ] : st[RDY],
addr_row = AW==22 ? addr[AW-1:AW-ROW] : addr[AW-2:AW-1-ROW],
rd_wr = rd | wr,
idle = st[0];
always @(posedge clk, posedge rst) begin
if( rst ) begin
in_busy <= 0; // |st[ (BALEN==16? READ+1 : RDY-2):READ]
in_busy64 <= 0; // |{st[BUSY:READ], do_read}
dok <= 0; // |st[RDY:DST]
dqm_busy <= 0; // |{st[RDY-2:READ]}
end else begin
if(next_st[READ]) in_busy <= 1;
else if( st[(BALEN==16? READ+1 : RDY-2)] || next_st[READ-1:0]!=0 ) in_busy<=0;
if(next_st[READ]) in_busy64 <= 1;
else if( st[BUSY] || next_st[READ-1:0]!=0 ) in_busy64<=0;
if(next_st[DST]) dok<=1;
else if( st[RDY] || next_st[DST-1:0]!=0 ) dok <= 0;
if(next_st[READ]) dqm_busy<=1;
else if(st[RDY-2] || next_st[READ-1:0]!=0) dqm_busy<=0;
end
end
always @(*) begin
rot_st = { st[STW-2:0], st[STW-1] };
next_st = st;
if( st[IDLE] ) begin
if(do_prech) next_st = rot_st;
if(do_act ) next_st = ONE<<ACT;
if(do_read ) next_st = ONE<<READ;
end
if( ( st[PRE_RD] && bg && !all_dqm ) ||
( st[PRE_ACT] && bg && !all_dqm && !all_act) ||
( !st[IDLE] && !st[PRE_ACT] && !st[PRE_RD] ) )
next_st = rot_st;
if( st[READ] && wr && !AUTOPRECH)
next_st = 1; // writes finish earlier
end
wire row_match = match && actd && !AUTOPRECH[0];
always @(*) begin
do_prech = 0;
do_act = 0;
do_read = 0;
if( bg ) begin
do_prech = !prechd && !row_match // not a good address
&& (st[IDLE]&&rd_wr);
do_act = ((st[IDLE] & rd_wr & prechd & ~actd) | st[PRE_ACT])
& ~all_act & ~all_dqm;
do_read = ((st[IDLE] & rd_wr & row_match) | st[PRE_RD]) &
(~all_dbusy & (~all_dbusy64 | rd) & ~all_dqm);
end
end
generate
if( HF==1 ) begin
always @(posedge clk, posedge rst) begin
if( rst ) begin
br <= 0;
end else begin
br <= 0;
if( (st[IDLE] || next_st[IDLE] || next_st[PRE_ACT] || next_st[PRE_RD]) && rd_wr ) begin
br <= 1;
if( next_st[PRE_RD] & (all_dbusy | (all_dbusy64&wr)) ) br <= 0; // Do not try to request
end
end
end
end else begin
always @(*) begin
br = 0;
if( (st[IDLE] || st[PRE_ACT] || st[PRE_RD]) && rd_wr ) begin
br = 1;
if( st[PRE_RD] & (all_dbusy | (all_dbusy64&wr)) ) br = 0; // Do not try to request
end
end
end
endgenerate
// module outputs
always @(*) begin
wr_busy = do_read & wr;
cmd = do_prech ? CMD_PRECHARGE : (
do_act ? CMD_ACTIVE : (
do_read ? (rd ? CMD_READ : CMD_WRITE ) : CMD_NOP ));
sdram_a[12:11] = addr_row[12:11];
sdram_a[10:0] = do_act ? addr_row[10:0] :
{ do_read ? AUTOPRECH[0] : PRECHARGE_ALL[0], addr[AW-1], addr[8:0]};
end
always @(posedge clk, posedge rst) begin
if( rst ) begin
prechd <= 0;
actd <= 0;
row <= 0;
st <= 1; // IDLE
last_act <= 0;
written <= 0;
end else begin
st <= next_st;
if( do_act ) begin
post_act <= 1;
last_act <= 1;
end else begin
last_act <= 0;
post_act <= last_act;
end
if( do_act ) begin
row <= addr_row;
prechd <= 0;
actd <= 1;
end
if( do_read ) written <= wr;
else if(st[0]) written<=0;
if( do_prech || set_prech || (do_read && AUTOPRECH)) begin
prechd <= 1;
actd <= 0;
end
end
end
endmodule

View File

@@ -0,0 +1,98 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 29-4-2021 */
module jtframe_sdram64_init #(parameter
HF =1,
BURSTLEN=64
) (
input rst,
input clk,
output reg init,
output reg [3:0] cmd,
output reg [12:0] sdram_a
);
localparam [13:0] INIT_WAIT = HF ? 14'd10_000 : 14'd5_000; // 100us for 96MHz/48MHz
// /CS /RAS /CAS /WE
localparam CMD_LOAD_MODE = 4'b0___0____0____0, // 0
CMD_REFRESH = 4'b0___0____0____1, // 1
CMD_PRECHARGE = 4'b0___0____1____0, // 2
CMD_ACTIVE = 4'b0___0____1____1, // 3
CMD_WRITE = 4'b0___1____0____0, // 4
CMD_READ = 4'b0___1____0____1, // 5
CMD_STOP = 4'b0___1____1____0, // 6 Burst terminate
CMD_NOP = 4'b0___1____1____1, // 7
CMD_INHIBIT = 4'b1___0____0____0; // 8
// initialization signals
reg [13:0] wait_cnt;
reg [ 2:0] init_st;
reg [ 3:0] init_cmd;
always @(posedge clk, posedge rst) begin
if( rst ) begin
// initialization loop
init <= 1;
wait_cnt <= INIT_WAIT; // wait for 100us
init_st <= 3'd0;
init_cmd <= CMD_NOP;
// SDRAM pins
cmd <= CMD_NOP;
sdram_a <= 13'd0;
end else if( init ) begin
if( |wait_cnt ) begin
wait_cnt <= wait_cnt-14'd1;
init_cmd <= CMD_NOP;
cmd <= init_cmd;
end else begin
sdram_a <= 13'd0;
if(!init_st[2]) init_st <= init_st+3'd1;
case(init_st)
3'd0: begin
init_cmd <= CMD_PRECHARGE;
sdram_a[10]<= 1; // all banks
wait_cnt <= 14'd2;
end
3'd1: begin
init_cmd <= CMD_REFRESH;
wait_cnt <= 14'd11;
end
3'd2: begin
init_cmd <= CMD_REFRESH;
wait_cnt <= 14'd11;
end
3'd3: begin
init_cmd <= CMD_LOAD_MODE;
sdram_a <= {10'b00_1_00_010_0,BURSTLEN==64?3'b010:(BURSTLEN==32?3'b001:3'b000)}; // CAS Latency = 2, burst = 1-4
wait_cnt <= 14'd3;
end
3'd4: begin
init <= 0;
end
default: begin
cmd <= init_cmd;
init <= 0;
end
endcase
end
end
end
endmodule

View File

@@ -0,0 +1,92 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 29-4-2021 */
module jtframe_sdram64_latch #(parameter LATCH=0, AW=22)(
input rst,
input clk,
input [AW-1:0] ba0_addr,
input [AW-1:0] ba1_addr,
input [AW-1:0] ba2_addr,
input [AW-1:0] ba3_addr,
output reg [AW-1:0] ba0_addr_l,
output reg [AW-1:0] ba1_addr_l,
output reg [AW-1:0] ba2_addr_l,
output reg [AW-1:0] ba3_addr_l,
input [ 12:0] ba0_row,
input [ 12:0] ba1_row,
input [ 12:0] ba2_row,
input [ 12:0] ba3_row,
input [3:0] rd,
input [3:0] wr,
input prog_en,
input prog_rd,
input prog_wr,
output reg [3:0] rd_l,
output reg [3:0] wr_l,
output reg [3:0] match,
output reg noreq
);
localparam RMSB = AW==22 ? AW-1 : AW-2,
RLSB = RMSB-12;
wire prog_rq = prog_en &(prog_wr | prog_rd);
generate
if( LATCH==1 ) begin
always @(posedge clk, posedge rst) begin
if( rst ) begin
ba0_addr_l <= 0;
ba1_addr_l <= 0;
ba2_addr_l <= 0;
ba3_addr_l <= 0;
wr_l <= 0;
rd_l <= 0;
noreq <= 1;
end else begin
ba0_addr_l <= ba0_addr;
ba1_addr_l <= ba1_addr;
ba2_addr_l <= ba2_addr;
ba3_addr_l <= ba3_addr;
match[0] <= ba0_addr[RMSB:RLSB]===ba0_row;
match[1] <= ba1_addr[RMSB:RLSB]===ba1_row;
match[2] <= ba2_addr[RMSB:RLSB]===ba2_row;
match[3] <= ba3_addr[RMSB:RLSB]===ba3_row;
wr_l <= wr;
rd_l <= rd;
noreq <= ~|{wr,rd,prog_rq};
end
end
end else begin
always @(*) begin
ba0_addr_l = ba0_addr;
ba1_addr_l = ba1_addr;
ba2_addr_l = ba2_addr;
ba3_addr_l = ba3_addr;
match[0] = ba0_addr[RMSB:RLSB]===ba0_row;
match[1] = ba1_addr[RMSB:RLSB]===ba1_row;
match[2] = ba2_addr[RMSB:RLSB]===ba2_row;
match[3] = ba3_addr[RMSB:RLSB]===ba3_row;
wr_l = wr;
rd_l = rd;
noreq = ~|{wr,rd,prog_rq};
end
end
endgenerate
endmodule

View File

@@ -0,0 +1,119 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 29-4-2021 */
module jtframe_sdram64_rfsh #(parameter HF=1, RFSHCNT=9)
(
input rst,
input clk,
input start,
output reg br,
input bg,
input noreq,
output reg rfshing,
output reg [3:0] cmd,
output reg help,
output [12:0] sdram_a
);
// Frequency limits before getting a tRFC error
// HF=0 -> 60MHz (16.67ns)
// HF=1 -> 100MHz (10ns)
localparam STW = 3+7-(HF==1? 0 : 4),
RFRSH= HF?2:1;
localparam CW=6;
localparam [STW-1:0] ONE=1;
// /CS /RAS /CAS /WE
localparam CMD_LOAD_MODE = 4'b0___0____0____0, // 0
CMD_REFRESH = 4'b0___0____0____1, // 1
CMD_PRECHARGE = 4'b0___0____1____0, // 2
CMD_ACTIVE = 4'b0___0____1____1, // 3
CMD_WRITE = 4'b0___1____0____0, // 4
CMD_READ = 4'b0___1____0____1, // 5
CMD_STOP = 4'b0___1____1____0, // 6 Burst terminate
CMD_NOP = 4'b0___1____1____1, // 7
CMD_INHIBIT = 4'b1___0____0____0; // 8
`ifdef SIMULATION
initial begin
if( RFSHCNT >= (1<<CW)-1 ) begin
$display("ERROR: RFSHCNT is too large for the size of CW (%m)");
$finish;
end
end
`endif
assign sdram_a = 13'h400; // used for precharging all banks
reg [CW-1:0] cnt;
reg [STW-1:0] st;
reg last_start;
wire [CW:0] next_cnt;
assign next_cnt = {1'b0, cnt} + RFSHCNT[CW-1:0];
always @(posedge clk, posedge rst) begin
if( rst ) begin
st <= 1;
cmd <= CMD_NOP;
cnt <= 0;
br <= 0;
rfshing <= 0;
help <= 0;
end else begin
// Forces a refresh if we have built up too much debt
if( next_cnt[CW] )
help <= 1;
if( next_cnt[CW:CW-1]==0 ) // at least half the debt must go
help <= 0;
last_start <= start;
if( start && !last_start ) begin
cnt <= help ? {CW{1'b1}} : next_cnt[CW-1:0]; // carry over from previous "frame"
end
if( cnt!=0 && !rfshing ) begin
br <= 1;
st <= 1;
end
if( bg ) begin
br <= 0;
rfshing <= 1;
end
if( rfshing || bg ) begin
st <= { st[STW-2:0], st[STW-1] };
end
if( st[STW-1] ) begin
if( cnt!=0 ) begin
cnt <= cnt - 1'd1;
if( !noreq ) begin
rfshing <= 0;
end else begin
st <= ONE << RFRSH; // do another refresh cycle as there are no requests
end
end else begin
rfshing <= 0;
end
end
cmd <= st[0] ? CMD_PRECHARGE : ( st[RFRSH] ? CMD_REFRESH : CMD_NOP );
end
end
endmodule

193
rtl/ipcores/k5289.v Normal file
View File

@@ -0,0 +1,193 @@
//================================================================================
// K0005289 Pre-SCC Wavetable Sound Generator
//
// Nemesis sound module
// Copyright © 2020-2022 LMN-san (@LmnSama),
// Olivier Scherler (@oscherler),
// Raki (Sehyeon Kim, @RCAVictorCo)
//
// Commercial use is prohibited.
//================================================================================
// CUSTOM CHIP pinout:
/* _____________
_| |_
GND(0) |_|1 42|_| VCC
_| |_
A(0) |_|2 41|_| /RESET
_| |_
A(1) |_|3 40|_| 1QE(4)
_| |_
A(2) |_|4 39|_| 1QD(3)
_| |_
A(3) |_|5 38|_| 1QC(2)
_| |_
A(4) |_|6 37|_| 1QB(1)
_| |_
A(5) |_|7 36|_| 1QA(0)
_| |_
A(6) |_|8 35|_| 2QE(4)
_| |_
A(7) |_|9 34|_| 2QD(3)
_| |_
A(8) |_|10 8A 33|_| 2QC(2)
_| |_
A(9) |_|11 32|_| 2QB(1)
_| |_
A(10) |_|12 31|_| 2QA(0)
_| |_
A(11) |_|13 30|_| T1(connect to gnd)
_| |_
CLK() |_|14 29|_| T0(connect to gnd)
_| |_
LD1() |_|15 28|_|
_| |_
TG1() |_|16 27|_|
_| |_
LD2() |_|17 26|_|
_| |_
TG2() |_|18 25|_|
_| |_
|_|19 24|_|
_| |_
|_|20 23|_|
_| |_
GND |_|21 22|_| GND
|_____________|
*/
module K005289
(
input i_RST_n, // RESET signal
input i_CLK, // Main clock
input i_CEN, // Clock enable
input i_LD1, //
input i_TG1, //
input i_LD2, //
input i_TG2, //
input [11:0] i_COUNTER, // 12 bits input counter to play frequency
output [4:0] o_Q1, // 5 bits output
output [4:0] o_Q2 // 5 bits output
);
////////////////////////////////////////////////////////////////////////////////////////////////////
wire [11:0] addrLD1, addrTG1, addrLD2, addrTG2;
// the 17 bits counters will serve 2 purposes count on the lower part on 12 bits and output
// the accumulated upper 5 bits part
reg [16:0] r_count1, r_count2;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Channel 1 LATCH
bus_ff #( .W( 12 ) ) ch1_ld_latch(
.rst ( ~i_RST_n ),
.clk ( i_CLK ),
.trig ( ~i_LD1 ),
.d ( i_COUNTER ),
.q ( addrLD1 ),
.q_n ( )
);
bus_ff #( .W( 12 ) ) ch1_tg_latch(
.rst ( ~i_RST_n ),
.clk ( i_CLK ),
.trig ( ~i_TG1 ),
.d ( addrLD1 ),
.q ( addrTG1 ),
.q_n ( )
);
// Channel 2 LATCH
bus_ff #( .W( 12 ) ) ch2_ld_latch(
.rst ( ~i_RST_n ),
.clk ( i_CLK ),
.trig ( ~i_LD2 ),
.d ( i_COUNTER ),
.q ( addrLD2 ),
.q_n ( )
);
bus_ff #( .W( 12 ) ) ch2_tg_latch(
.rst ( ~i_RST_n ),
.clk ( i_CLK ),
.trig ( ~i_TG2 ),
.d ( addrLD2 ),
.q ( addrTG2 ),
.q_n ( )
);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Channel 1 COUNTERS
// addrTG1 = IN : 12 bits data input
// i_CLK = IN : clock input
// i_CEN = IN : clock enable
// i_RST_n = IN : reset at 0
always @( posedge i_CLK ) begin
if (~i_RST_n) begin // if n_reset = 0
r_count1 <= 17'd0; // 12 bits + 5 bits for the counter output
r_count2 <= 17'd0; // 12 bits + 5 bits for the counter output
end else if (i_CEN) begin // if i_CEN pulse = 1
// COUNTER 1
if(r_count1[11:0] == 12'hFFF) begin
r_count1 <= r_count1 + 17'd1; // we need to add 1 before the re-set of the lower value to be sure we increment the upper part for the output
r_count1[11:0] <= addrTG1; // re-set to the tone in addrTG1 memory register
end else begin
r_count1 <= r_count1 + 17'd1;
end
// COUNTER 2
if(r_count2[11:0] == 12'hFFF) begin
r_count2 <= r_count2 + 17'd1; // we need to add 1 before the re-set of the lower value to be sure we increment the upper part for the output
r_count2[11:0] <= addrTG2; // re-set to the tone in addrTG2 memory register
end else begin
r_count2 <= r_count2 + 17'd1;
end
end
end
assign o_Q1 = r_count1[16:12]; // we output only the upper part of the counter
assign o_Q2 = r_count2[16:12]; // we output only the upper part of the counter
endmodule
module bus_ff #( parameter W=1 ) (
input clk,
input rst,
input trig,
input [W-1:0] d,
output [W-1:0] q,
output [W-1:0] q_n
);
reg trig_prev;
reg [W-1:0] state;
always @( posedge clk ) begin
if( rst ) begin
state <= {W{1'b0}};
trig_prev <= 1'b1;
end else begin
if( trig & ~trig_prev ) begin
state <= d;
end
trig_prev <= trig;
end
end
assign q = state;
assign q_n = ~state;
endmodule

Some files were not shown because too many files have changed in this diff Show More