mirror of
https://github.com/MiSTer-devel/ZXNext_MISTer.git
synced 2026-04-19 03:05:38 +00:00
Support for TZX.
This commit is contained in:
141
ZXNext.sv
141
ZXNext.sv
@@ -173,14 +173,13 @@ module emu
|
||||
);
|
||||
|
||||
assign USER_OUT = '1;
|
||||
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = '0;
|
||||
|
||||
assign AUDIO_S = 0; // 1 - signed audio samples, 0 - unsigned
|
||||
assign AUDIO_MIX = status[4:3];
|
||||
|
||||
assign LED_DISK = 0;
|
||||
assign LED_POWER = 0;
|
||||
assign LED_USER = sd_act;
|
||||
assign LED_USER = sd_act | tape_led;
|
||||
assign BUTTONS = 0;
|
||||
|
||||
assign UART_RTS = 0;
|
||||
@@ -203,6 +202,8 @@ localparam CONF_STR = {
|
||||
"S0,VHD,Mount C:;",
|
||||
"S1,VHD,Mount D:;",
|
||||
"O1,Hard Reset on C: mount,No,Yes;",
|
||||
"-;",
|
||||
"F1,TZX,Load Tape;",
|
||||
"-;",
|
||||
"O78,Aspect Ratio,Original,Full Screen,[ARC1],[ARC2];",
|
||||
"O56,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;",
|
||||
@@ -263,6 +264,13 @@ wire [21:0] gamma_bus;
|
||||
|
||||
wire [64:0] RTC;
|
||||
|
||||
wire ioctl_wr;
|
||||
wire [24:0] ioctl_addr;
|
||||
wire [15:0] ioctl_dout;
|
||||
wire ioctl_download;
|
||||
wire [7:0] ioctl_index;
|
||||
wire ioctl_wait;
|
||||
|
||||
hps_io #(.STRLEN($size(CONF_STR)>>3), .VDNUM(2), .WIDE(1)) hps_io
|
||||
(
|
||||
.clk_sys(clk_sys),
|
||||
@@ -289,6 +297,13 @@ hps_io #(.STRLEN($size(CONF_STR)>>3), .VDNUM(2), .WIDE(1)) hps_io
|
||||
.img_mounted(img_mounted),
|
||||
.img_size(img_size),
|
||||
|
||||
.ioctl_wr(ioctl_wr),
|
||||
.ioctl_addr(ioctl_addr),
|
||||
.ioctl_dout(ioctl_dout),
|
||||
.ioctl_download(ioctl_download),
|
||||
.ioctl_index(ioctl_index),
|
||||
.ioctl_wait(ioctl_wait),
|
||||
|
||||
.ps2_key(ps2_key),
|
||||
.ps2_mouse(ps2_mouse),
|
||||
.ps2_mouse_ext(ps2_mouse_ext),
|
||||
@@ -576,7 +591,7 @@ rtc #(28000000) rtc
|
||||
wire tape_in;
|
||||
wire tape_adc, tape_adc_act;
|
||||
|
||||
assign tape_in = tape_adc_act & tape_adc;
|
||||
assign tape_in = tape_adc_act ? tape_adc : audio_out;
|
||||
|
||||
ltc2308_tape #(.CLK_RATE(28000000)) ltc2308_tape
|
||||
(
|
||||
@@ -586,4 +601,124 @@ ltc2308_tape #(.CLK_RATE(28000000)) ltc2308_tape
|
||||
.active(tape_adc_act)
|
||||
);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
assign DDRAM_CLK = CLK_112;
|
||||
wire clk_tape = CLK_112;
|
||||
|
||||
reg tape_ce;
|
||||
always @(posedge clk_tape) begin
|
||||
reg [4:0] div;
|
||||
reg [1:0] speed;
|
||||
|
||||
div <= div + 1'd1;
|
||||
if(&div) speed <= cpu_speed;
|
||||
case(speed)
|
||||
0: tape_ce <= !div[4:0];
|
||||
1: tape_ce <= !div[3:0];
|
||||
2: tape_ce <= !div[2:0] & ~RAM_A_WAIT;
|
||||
3: tape_ce <= !div[1:0] & ~RAM_A_WAIT;
|
||||
endcase
|
||||
end
|
||||
|
||||
ddram ddram
|
||||
(
|
||||
.*,
|
||||
|
||||
.wraddr(ioctl_addr[24:1]),
|
||||
.din(ioctl_dout),
|
||||
.we_req(ddram_we_req),
|
||||
.we_ack(ddram_we_ack),
|
||||
|
||||
.rdaddr(tape_addr),
|
||||
.dout(tape_data),
|
||||
.rom_req(tape_req),
|
||||
.rom_ack(tape_ack)
|
||||
);
|
||||
|
||||
reg ddram_we_req;
|
||||
wire ddram_we_ack;
|
||||
always @(posedge clk_sys) if(ioctl_wr) ddram_we_req <= ~ddram_we_req;
|
||||
|
||||
assign ioctl_wait = ddram_we_req ^ ddram_we_ack;
|
||||
wire tape_download = ioctl_download && (ioctl_index == 1);
|
||||
|
||||
wire tzx_stop, tzx_stop48k, tzx_loop_start, tzx_loop_next, tzx_audio, tzx_req;
|
||||
|
||||
tzxplayer #(.TZX_MS(3500)) tzxplayer
|
||||
(
|
||||
.clk(clk_tape),
|
||||
.ce(tape_ce),
|
||||
.tzx_req(tzx_req),
|
||||
.tzx_ack(tape_ack),
|
||||
.loop_start(tzx_loop_start),
|
||||
.loop_next(tzx_loop_next),
|
||||
.stop(tzx_stop),
|
||||
.stop48k(tzx_stop48k),
|
||||
.restart_tape(~tape_ready | tape_restart),
|
||||
.host_tap_in(tape_data),
|
||||
.cass_read(tzx_audio),
|
||||
.cass_motor(!play_pause)
|
||||
);
|
||||
|
||||
wire [7:0] tape_data;
|
||||
reg tape_req;
|
||||
wire tape_ack;
|
||||
|
||||
reg key_restart, tape_restart, play_pause;
|
||||
reg audio_out;
|
||||
reg [24:0] tape_addr;
|
||||
reg tape_ready;
|
||||
always @(posedge clk_tape) begin
|
||||
reg old_download;
|
||||
reg [24:0] tape_len, tzx_loop_addr;
|
||||
reg key_stb1, key_stb2;
|
||||
reg [24:0] addr;
|
||||
|
||||
tape_restart <= tape_download;
|
||||
|
||||
key_stb1 <= ps2_key[10];
|
||||
key_stb2 <= key_stb1;
|
||||
if(key_stb1 ^ key_stb2) begin
|
||||
if(ps2_key[8:0] == 'h03 && ps2_key[9]) play_pause <= ~play_pause; // F5
|
||||
if(ps2_key[8:0] == 'h0B) tape_restart <= 1; // F6
|
||||
if(ps2_key[8:0] == 'h83) tape_ready <= 0; // F7
|
||||
end
|
||||
|
||||
if(reset) tape_ready <= 0;
|
||||
if(!tape_ready) play_pause <= 1;
|
||||
|
||||
tape_req <= tzx_req;
|
||||
if(tape_restart) begin
|
||||
addr <= 0;
|
||||
tape_addr <= 0;
|
||||
play_pause <= 1;
|
||||
end
|
||||
else if(tape_req ^ tzx_req) begin
|
||||
tape_addr <= addr;
|
||||
addr <= addr + 1'd1;
|
||||
if(addr >= tape_len) tape_ready <= 0;
|
||||
end
|
||||
|
||||
audio_out <= tzx_audio;
|
||||
if(tzx_stop | tzx_stop48k) play_pause <= 1;
|
||||
if(tzx_loop_start) tzx_loop_addr <= addr;
|
||||
if(tzx_loop_next) begin
|
||||
addr <= tzx_loop_addr + 1'd1;
|
||||
tape_addr <= tzx_loop_addr;
|
||||
end
|
||||
|
||||
old_download <= tape_download;
|
||||
if(old_download & ~tape_download) begin
|
||||
tape_len <= ioctl_addr;
|
||||
tape_ready <= 1;
|
||||
play_pause <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
wire tape_led = act_cnt[22] ? act_cnt[21:14] > act_cnt[7:0] : act_cnt[21:14] <= act_cnt[7:0];
|
||||
|
||||
reg [22:0] act_cnt;
|
||||
always @(posedge clk_sys) if(~play_pause || ~(tape_ready ^ act_cnt[22]) || act_cnt[21:0]) act_cnt <= act_cnt + 1'd1;
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
set_global_assignment -name QIP_FILE rtl/mister/MiSTer.qip
|
||||
set_global_assignment -name VHDL_FILE rtl/audio/ym2149.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/audio/turbosound.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/audio/soundrive.vhd
|
||||
@@ -39,10 +40,5 @@ set_global_assignment -name VHDL_FILE rtl/rom/bootrom.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/device/ctc_chan.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/device/ctc.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/zxnext.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/mister/ps2_keyb.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/mister/bram.vhd
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/mister/rtc.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/mister/sdram.sv
|
||||
set_global_assignment -name VHDL_FILE rtl/mister/zxnext_top.vhd
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE ZXNext.sv
|
||||
set_global_assignment -name SDC_FILE ZXNext.sdc
|
||||
|
||||
7
rtl/mister/MiSTer.qip
Normal file
7
rtl/mister/MiSTer.qip
Normal file
@@ -0,0 +1,7 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ps2_keyb.vhd ]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) bram.vhd ]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) tzxplayer.vhd ]
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) rtc.sv ]
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddram.sv ]
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sdram.sv ]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) zxnext_top.vhd ]
|
||||
119
rtl/mister/ddram.sv
Normal file
119
rtl/mister/ddram.sv
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// ddram.v
|
||||
// Copyright (c) 2021 Sorgelig
|
||||
//
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ------------------------------------------
|
||||
//
|
||||
|
||||
// 16-bit version
|
||||
|
||||
module ddram
|
||||
(
|
||||
input 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,
|
||||
|
||||
input [27:1] wraddr,
|
||||
input [15:0] din,
|
||||
input we_req,
|
||||
output reg we_ack,
|
||||
|
||||
input [27:0] rdaddr,
|
||||
output [7:0] dout,
|
||||
input rom_req,
|
||||
output reg rom_ack
|
||||
);
|
||||
|
||||
assign DDRAM_BURSTCNT = ram_burst;
|
||||
assign DDRAM_BE = ram_be | {8{ram_read}};
|
||||
assign DDRAM_ADDR = {4'b0011, ram_address}; // RAM at 0x30000000
|
||||
assign DDRAM_RD = ram_read;
|
||||
assign DDRAM_DIN = ram_data;
|
||||
assign DDRAM_WE = ram_write;
|
||||
|
||||
assign dout = ram_q[{rdaddr[2:0], 3'b000} +:8];
|
||||
|
||||
reg [7:0] ram_burst;
|
||||
reg [63:0] ram_q, next_q;
|
||||
reg [63:0] ram_data;
|
||||
reg [27:3] ram_address, cache_addr;
|
||||
reg ram_read = 0;
|
||||
reg ram_write = 0;
|
||||
reg [7:0] ram_be = 0;
|
||||
|
||||
always @(posedge DDRAM_CLK) begin
|
||||
reg [1:0] state = 0;
|
||||
|
||||
if(rom_req != rom_ack && state != 1 && cache_addr == rdaddr[27:3]) rom_ack <= rom_req;
|
||||
|
||||
if(!DDRAM_BUSY) begin
|
||||
ram_write <= 0;
|
||||
ram_read <= 0;
|
||||
|
||||
case(state)
|
||||
0: if(we_ack != we_req) begin
|
||||
ram_be <= 8'd3<<{wraddr[2:1],1'b0};
|
||||
ram_data <= {4{din}};
|
||||
ram_address <= wraddr[27:3];
|
||||
ram_write <= 1;
|
||||
ram_burst <= 1;
|
||||
cache_addr <= '1;
|
||||
cache_addr[3] <= 0;
|
||||
we_ack <= we_req;
|
||||
end
|
||||
else if(rom_req != rom_ack) begin
|
||||
if((cache_addr+1'd1) == rdaddr[27:3]) begin
|
||||
rom_ack <= rom_req;
|
||||
ram_q <= next_q;
|
||||
cache_addr <= rdaddr[27:3];
|
||||
ram_address <= rdaddr[27:3]+1'd1;
|
||||
ram_read <= 1;
|
||||
ram_burst <= 1;
|
||||
state <= 2;
|
||||
end
|
||||
else if(cache_addr != rdaddr[27:3]) begin
|
||||
ram_address <= rdaddr[27:3];
|
||||
cache_addr <= rdaddr[27:3];
|
||||
ram_read <= 1;
|
||||
ram_burst <= 2;
|
||||
state <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
1: if(DDRAM_DOUT_READY) begin
|
||||
ram_q <= DDRAM_DOUT;
|
||||
rom_ack <= rom_req;
|
||||
state <= 2;
|
||||
end
|
||||
|
||||
2: if(DDRAM_DOUT_READY) begin
|
||||
next_q <= DDRAM_DOUT;
|
||||
state <= 0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
528
rtl/mister/tzxplayer.vhd
Normal file
528
rtl/mister/tzxplayer.vhd
Normal file
@@ -0,0 +1,528 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- TZX player
|
||||
-- by György Szombathelyi
|
||||
-- basic idea for the structure based on c1530 tap player by darfpga
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use IEEE.STD_LOGIC_ARITH.ALL;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity tzxplayer is
|
||||
generic (
|
||||
TZX_MS : integer := 64000; -- CE periods for one milliseconds
|
||||
-- Default: ZX Spectrum
|
||||
NORMAL_PILOT_LEN : integer := 2168;
|
||||
NORMAL_SYNC1_LEN : integer := 667;
|
||||
NORMAL_SYNC2_LEN : integer := 735;
|
||||
NORMAL_ZERO_LEN : integer := 855;
|
||||
NORMAL_ONE_LEN : integer := 1710;
|
||||
NORMAL_PILOT_PULSES : integer := 4031
|
||||
|
||||
-- Amstrad CPC
|
||||
--NORMAL_PILOT_LEN : integer := 2000;
|
||||
--NORMAL_SYNC1_LEN : integer := 855;
|
||||
--NORMAL_SYNC2_LEN : integer := 855;
|
||||
--NORMAL_ZERO_LEN : integer := 855;
|
||||
--NORMAL_ONE_LEN : integer := 1710;
|
||||
--NORMAL_PILOT_PULSES : integer := 4096;
|
||||
);
|
||||
port(
|
||||
clk : in std_logic;
|
||||
ce : in std_logic;
|
||||
restart_tape : in std_logic;
|
||||
|
||||
host_tap_in : in std_logic_vector(7 downto 0); -- 8bits fifo input
|
||||
tzx_req : buffer std_logic; -- request for new byte (edge trigger)
|
||||
tzx_ack : in std_logic; -- new data available
|
||||
loop_start : out std_logic; -- active for one clock if a loop starts
|
||||
loop_next : out std_logic; -- active for one clock at the next iteration
|
||||
stop : out std_logic; -- tape should be stopped
|
||||
stop48k : out std_logic; -- tape should be stopped in 48k mode
|
||||
|
||||
cass_read : buffer std_logic; -- tape read signal
|
||||
cass_motor : in std_logic -- 1 = tape motor is powered
|
||||
);
|
||||
end tzxplayer;
|
||||
|
||||
architecture struct of tzxplayer is
|
||||
|
||||
|
||||
signal tap_fifo_do : std_logic_vector(7 downto 0);
|
||||
signal tick_cnt : std_logic_vector(16 downto 0);
|
||||
signal wave_cnt : std_logic_vector(15 downto 0);
|
||||
signal wave_period : std_logic;
|
||||
signal skip_bytes : std_logic;
|
||||
signal playing : std_logic; -- 1 = tap or wav file is playing
|
||||
signal bit_cnt : std_logic_vector(2 downto 0);
|
||||
|
||||
type tzx_state_t is (
|
||||
TZX_HEADER,
|
||||
TZX_NEWBLOCK,
|
||||
TZX_LOOP_START,
|
||||
TZX_LOOP_END,
|
||||
TZX_PAUSE,
|
||||
TZX_PAUSE2,
|
||||
TZX_STOP48K,
|
||||
TZX_HWTYPE,
|
||||
TZX_TEXT,
|
||||
TZX_MESSAGE,
|
||||
TZX_ARCHIVE_INFO,
|
||||
TZX_CUSTOM_INFO,
|
||||
TZX_GLUE,
|
||||
TZX_TONE,
|
||||
TZX_PULSES,
|
||||
TZX_DATA,
|
||||
TZX_NORMAL,
|
||||
TZX_TURBO,
|
||||
TZX_PLAY_TONE,
|
||||
TZX_PLAY_SYNC1,
|
||||
TZX_PLAY_SYNC2,
|
||||
TZX_PLAY_TAPBLOCK,
|
||||
TZX_PLAY_TAPBLOCK2,
|
||||
TZX_PLAY_TAPBLOCK3,
|
||||
TZX_PLAY_TAPBLOCK4,
|
||||
TZX_DIRECT,
|
||||
TZX_DIRECT2,
|
||||
TZX_DIRECT3);
|
||||
|
||||
signal tzx_state: tzx_state_t;
|
||||
|
||||
signal tzx_offset : std_logic_vector( 7 downto 0);
|
||||
signal pause_len : std_logic_vector(15 downto 0);
|
||||
signal ms_counter : std_logic_vector(15 downto 0);
|
||||
signal pilot_l : std_logic_vector(15 downto 0);
|
||||
signal sync1_l : std_logic_vector(15 downto 0);
|
||||
signal sync2_l : std_logic_vector(15 downto 0);
|
||||
signal zero_l : std_logic_vector(15 downto 0);
|
||||
signal one_l : std_logic_vector(15 downto 0);
|
||||
signal pilot_pulses : std_logic_vector(15 downto 0);
|
||||
signal last_byte_bits : std_logic_vector( 3 downto 0);
|
||||
signal data_len : std_logic_vector(23 downto 0);
|
||||
signal pulse_len : std_logic_vector(15 downto 0);
|
||||
signal end_period : std_logic;
|
||||
signal cass_motor_D : std_logic;
|
||||
signal motor_counter : std_logic_vector(21 downto 0);
|
||||
signal loop_iter : std_logic_vector(15 downto 0);
|
||||
signal data_len_dword : std_logic_vector(31 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
tap_fifo_do <= host_tap_in;
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if restart_tape = '1' then
|
||||
|
||||
tzx_offset <= (others => '0');
|
||||
tzx_state <= TZX_HEADER;
|
||||
pulse_len <= (others => '0');
|
||||
motor_counter <= (others => '0');
|
||||
wave_period <= '0';
|
||||
playing <= '0';
|
||||
tzx_req <= tzx_ack;
|
||||
loop_start <= '0';
|
||||
loop_next <= '0';
|
||||
loop_iter <= (others => '0');
|
||||
|
||||
else
|
||||
|
||||
-- simulate tape motor momentum
|
||||
-- don't change the playing state if the motor is switched in 50 ms
|
||||
-- Opera Soft K17 protection needs this!
|
||||
cass_motor_D <= cass_motor;
|
||||
if cass_motor_D /= cass_motor then
|
||||
motor_counter <= CONV_STD_LOGIC_VECTOR(50*TZX_MS, motor_counter'length);
|
||||
elsif motor_counter /= 0 then
|
||||
if ce = '1' then motor_counter <= motor_counter - 1; end if;
|
||||
else
|
||||
playing <= cass_motor;
|
||||
end if;
|
||||
|
||||
if playing = '0' then
|
||||
--cass_read <= '1';
|
||||
end if;
|
||||
|
||||
if pulse_len /= 0 then
|
||||
if ce = '1' then
|
||||
tick_cnt <= tick_cnt + 3500;
|
||||
if tick_cnt >= (TZX_MS - 3500) then
|
||||
tick_cnt <= tick_cnt - (TZX_MS - 3500);
|
||||
wave_cnt <= wave_cnt + 1;
|
||||
if wave_cnt = pulse_len then
|
||||
wave_cnt <= (others => '0');
|
||||
cass_read <= wave_period;
|
||||
wave_period <= not wave_period;
|
||||
if wave_period = end_period then
|
||||
pulse_len <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
tick_cnt <= (others => '0');
|
||||
wave_cnt <= (others => '0');
|
||||
end if;
|
||||
|
||||
loop_start <= '0';
|
||||
loop_next <= '0';
|
||||
stop <= '0';
|
||||
stop48k <= '0';
|
||||
|
||||
if playing = '1' and pulse_len = 0 and tzx_req = tzx_ack then
|
||||
|
||||
tzx_req <= not tzx_ack; -- default request for new data
|
||||
|
||||
case tzx_state is
|
||||
when TZX_HEADER =>
|
||||
cass_read <= '1';
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"0A" then -- skip 9 bytes, offset lags 1
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_NEWBLOCK =>
|
||||
tzx_offset <= (others=>'0');
|
||||
ms_counter <= (others=>'0');
|
||||
case tap_fifo_do is
|
||||
when x"10" => tzx_state <= TZX_NORMAL;
|
||||
when x"11" => tzx_state <= TZX_TURBO;
|
||||
when x"12" => tzx_state <= TZX_TONE;
|
||||
when x"13" => tzx_state <= TZX_PULSES;
|
||||
when x"14" => tzx_state <= TZX_DATA;
|
||||
when x"15" => tzx_state <= TZX_DIRECT;
|
||||
when x"18" => null; -- CSW recording (not implemented)
|
||||
when x"19" => null; -- Generalized data block (not implemented)
|
||||
when x"20" => tzx_state <= TZX_PAUSE;
|
||||
when x"21" => tzx_state <= TZX_TEXT; -- Group start
|
||||
when x"22" => null; -- Group end
|
||||
when x"23" => null; -- Jump to block (not implemented)
|
||||
when x"24" => tzx_state <= TZX_LOOP_START;
|
||||
when x"25" => tzx_state <= TZX_LOOP_END;
|
||||
when x"26" => null; -- Call sequence (not implemented)
|
||||
when x"27" => null; -- Return from sequence (not implemented)
|
||||
when x"28" => null; -- Select block (not implemented)
|
||||
when x"2A" => tzx_state <= TZX_STOP48K;
|
||||
when x"2B" => null; -- Set signal level (not implemented)
|
||||
when x"30" => tzx_state <= TZX_TEXT;
|
||||
when x"31" => tzx_state <= TZX_MESSAGE;
|
||||
when x"32" => tzx_state <= TZX_ARCHIVE_INFO;
|
||||
when x"33" => tzx_state <= TZX_HWTYPE;
|
||||
when x"35" => tzx_state <= TZX_CUSTOM_INFO;
|
||||
when x"5A" => tzx_state <= TZX_GLUE;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
when TZX_LOOP_START =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then loop_iter( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then
|
||||
loop_iter(15 downto 8) <= tap_fifo_do;
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
loop_start <= '1';
|
||||
end if;
|
||||
|
||||
when TZX_LOOP_END =>
|
||||
if loop_iter > 1 then
|
||||
loop_iter <= loop_iter - 1;
|
||||
loop_next <= '1';
|
||||
else
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
end if;
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
|
||||
when TZX_PAUSE =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then
|
||||
pause_len(7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then
|
||||
pause_len(15 downto 8) <= tap_fifo_do;
|
||||
tzx_state <= TZX_PAUSE2;
|
||||
if pause_len(7 downto 0) = 0 and tap_fifo_do = 0 then
|
||||
stop <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_PAUSE2 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
if ms_counter /= 0 then
|
||||
if ce = '1' then
|
||||
ms_counter <= ms_counter - 1;
|
||||
-- Set pulse level to low after 1 ms
|
||||
if ms_counter = 1 then
|
||||
wave_period <= '0';
|
||||
end_period <= '0';
|
||||
cass_read <= '0';
|
||||
end if;
|
||||
end if;
|
||||
elsif pause_len /= 0 then
|
||||
pause_len <= pause_len - 1;
|
||||
ms_counter <= conv_std_logic_vector(TZX_MS, 16);
|
||||
else
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_STOP48K =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"03" then
|
||||
stop48k <= '1';
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_HWTYPE =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
-- 0, 1-3, 1-3, ...
|
||||
if tzx_offset = x"00" then data_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then
|
||||
if data_len(7 downto 0) = x"01" then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
else
|
||||
data_len(7 downto 0) <= data_len(7 downto 0) - 1;
|
||||
tzx_offset <= x"01";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_MESSAGE =>
|
||||
-- skip display time, then then same as TEXT DESRCRIPTION
|
||||
tzx_state <= TZX_TEXT;
|
||||
|
||||
when TZX_TEXT =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then data_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = data_len(7 downto 0) then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_ARCHIVE_INFO =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then data_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then data_len(15 downto 8) <= tap_fifo_do;
|
||||
else
|
||||
tzx_offset <= x"02";
|
||||
data_len <= data_len - 1;
|
||||
if data_len = 1 then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_CUSTOM_INFO =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"10" then data_len_dword( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"11" then data_len_dword(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"12" then data_len_dword(23 downto 16) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"13" then data_len_dword(31 downto 24) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"14" then
|
||||
tzx_offset <= x"14";
|
||||
if data_len_dword = 1 then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
else
|
||||
data_len_dword <= data_len_dword - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_GLUE =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"08" then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_TONE =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
-- 0, 1, 2, 3, 4, 4, 4, ...
|
||||
if tzx_offset = x"00" then pilot_l( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then pilot_l(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then pilot_pulses( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
pilot_pulses(15 downto 8) <= tap_fifo_do;
|
||||
else
|
||||
tzx_offset <= x"04";
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
if pilot_pulses = 0 then
|
||||
tzx_req <= not tzx_ack; -- default request for new data
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
else
|
||||
pilot_pulses <= pilot_pulses - 1;
|
||||
end_period <= wave_period;
|
||||
pulse_len <= pilot_l;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_PULSES =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
-- 0, 1-2+3, 1-2+3, ...
|
||||
if tzx_offset = x"00" then data_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then one_l( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
end_period <= wave_period;
|
||||
pulse_len <= tap_fifo_do & one_l( 7 downto 0);
|
||||
elsif tzx_offset = x"03" then
|
||||
if data_len(7 downto 0) = x"01" then
|
||||
tzx_state <= TZX_NEWBLOCK;
|
||||
else
|
||||
data_len(7 downto 0) <= data_len(7 downto 0) - 1;
|
||||
tzx_offset <= x"01";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when TZX_DATA =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then zero_l ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then zero_l (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then one_l ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then one_l (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"04" then last_byte_bits <= tap_fifo_do(3 downto 0);
|
||||
elsif tzx_offset = x"05" then pause_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"06" then pause_len(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"07" then data_len ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"08" then data_len (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"09" then
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
data_len (23 downto 16) <= tap_fifo_do;
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK;
|
||||
end if;
|
||||
|
||||
when TZX_NORMAL =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then pause_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then pause_len(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then data_len ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
data_len(15 downto 8) <= tap_fifo_do;
|
||||
data_len(23 downto 16) <= (others => '0');
|
||||
pilot_l <= conv_std_logic_vector(NORMAL_PILOT_LEN, 16);
|
||||
sync1_l <= conv_std_logic_vector(NORMAL_SYNC1_LEN, 16);
|
||||
sync2_l <= conv_std_logic_vector(NORMAL_SYNC2_LEN, 16);
|
||||
zero_l <= conv_std_logic_vector(NORMAL_ZERO_LEN, 16);
|
||||
one_l <= conv_std_logic_vector(NORMAL_ONE_LEN, 16);
|
||||
pilot_pulses <= conv_std_logic_vector(NORMAL_PILOT_PULSES, 16);
|
||||
last_byte_bits <= "1000";
|
||||
tzx_state <= TZX_PLAY_TONE;
|
||||
end if;
|
||||
|
||||
when TZX_TURBO =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then pilot_l( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"01" then pilot_l(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then sync1_l( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then sync1_l(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"04" then sync2_l( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"05" then sync2_l(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"06" then zero_l ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"07" then zero_l (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"08" then one_l ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"09" then one_l (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"0A" then pilot_pulses( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"0B" then pilot_pulses(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"0C" then last_byte_bits <= tap_fifo_do(3 downto 0);
|
||||
elsif tzx_offset = x"0D" then pause_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"0E" then pause_len(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"0F" then data_len ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"10" then data_len (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"11" then
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
data_len (23 downto 16) <= tap_fifo_do;
|
||||
tzx_state <= TZX_PLAY_TONE;
|
||||
end if;
|
||||
|
||||
when TZX_PLAY_TONE =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
end_period <= not wave_period;
|
||||
pulse_len <= pilot_l;
|
||||
if pilot_pulses /= 0 then
|
||||
pilot_pulses <= pilot_pulses - 1;
|
||||
else
|
||||
tzx_state <= TZX_PLAY_SYNC1;
|
||||
end if;
|
||||
|
||||
when TZX_PLAY_SYNC1 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
end_period <= wave_period;
|
||||
pulse_len <= sync1_l;
|
||||
tzx_state <= TZX_PLAY_SYNC2;
|
||||
|
||||
when TZX_PLAY_SYNC2 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
end_period <= wave_period;
|
||||
pulse_len <= sync2_l;
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK;
|
||||
|
||||
when TZX_PLAY_TAPBLOCK =>
|
||||
bit_cnt <= "111";
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK2;
|
||||
|
||||
when TZX_PLAY_TAPBLOCK2 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
bit_cnt <= bit_cnt - 1;
|
||||
if bit_cnt = "000" or (data_len = 1 and ((bit_cnt = (8 - last_byte_bits)) or (last_byte_bits = 0))) then
|
||||
data_len <= data_len - 1;
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK3;
|
||||
end if;
|
||||
end_period <= not wave_period;
|
||||
if tap_fifo_do(CONV_INTEGER(bit_cnt)) = '0' then
|
||||
pulse_len <= zero_l;
|
||||
else
|
||||
pulse_len <= one_l;
|
||||
end if;
|
||||
|
||||
when TZX_PLAY_TAPBLOCK3 =>
|
||||
if data_len = 0 then
|
||||
tzx_state <= TZX_PAUSE2;
|
||||
else
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK4;
|
||||
end if;
|
||||
|
||||
when TZX_PLAY_TAPBLOCK4 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
tzx_state <= TZX_PLAY_TAPBLOCK2;
|
||||
|
||||
when TZX_DIRECT =>
|
||||
tzx_offset <= tzx_offset + 1;
|
||||
if tzx_offset = x"00" then zero_l ( 7 downto 0) <= tap_fifo_do; -- here this is used for one bit, too
|
||||
elsif tzx_offset = x"01" then zero_l (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"02" then pause_len ( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"03" then pause_len (15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"04" then last_byte_bits <= tap_fifo_do(3 downto 0);
|
||||
elsif tzx_offset = x"05" then data_len( 7 downto 0) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"06" then data_len(15 downto 8) <= tap_fifo_do;
|
||||
elsif tzx_offset = x"07" then
|
||||
data_len(23 downto 16) <= tap_fifo_do;
|
||||
tzx_state <= TZX_DIRECT2;
|
||||
bit_cnt <= "111";
|
||||
end if;
|
||||
|
||||
when TZX_DIRECT2 =>
|
||||
tzx_req <= tzx_ack; -- don't request new byte
|
||||
bit_cnt <= bit_cnt - 1;
|
||||
if bit_cnt = "000" or (data_len = 1 and ((bit_cnt = (8 - last_byte_bits)) or (last_byte_bits = 0))) then
|
||||
data_len <= data_len - 1;
|
||||
tzx_state <= TZX_DIRECT3;
|
||||
end if;
|
||||
|
||||
pulse_len <= zero_l;
|
||||
cass_read <= tap_fifo_do(CONV_INTEGER(bit_cnt));
|
||||
wave_period <= tap_fifo_do(CONV_INTEGER(bit_cnt));
|
||||
end_period <= tap_fifo_do(CONV_INTEGER(bit_cnt));
|
||||
|
||||
when TZX_DIRECT3 =>
|
||||
if data_len = 0 then
|
||||
tzx_state <= TZX_PAUSE2;
|
||||
else
|
||||
tzx_state <= TZX_DIRECT2;
|
||||
end if;
|
||||
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
end if; -- play tzx
|
||||
|
||||
end if;
|
||||
end if; -- clk
|
||||
end process;
|
||||
|
||||
end struct;
|
||||
@@ -43,7 +43,7 @@ entity zxnext_top is
|
||||
SW_RESET : in std_logic;
|
||||
|
||||
CPU_SPEED : out std_logic_vector(1 downto 0);
|
||||
CPU_WAIT : in std_logic := '0';
|
||||
CPU_WAIT : in std_logic := '0';
|
||||
|
||||
RAM_A_ADDR : out std_logic_vector(20 downto 0); -- 2MB memory space
|
||||
RAM_A_REQ : out std_logic; -- '1' indicates memory request on next rising edge
|
||||
@@ -222,7 +222,7 @@ begin
|
||||
-- CLOCKS --------------------------------------------------
|
||||
------------------------------------------------------------
|
||||
|
||||
CPU_SPEED <= zxn_cpu_speed;
|
||||
CPU_SPEED <= zxn_cpu_speed2;
|
||||
|
||||
-- cpu clock selection
|
||||
process (CLK_28)
|
||||
@@ -245,8 +245,8 @@ begin
|
||||
CLK_i0 <= clk_28_div(0);
|
||||
end case;
|
||||
|
||||
if clk_28_div(1 downto 0) = "11" and zxn_cpu_speed /= "11" then
|
||||
zxn_cpu_speed2 <= zxn_cpu_speed;
|
||||
if clk_28_div(1 downto 0) = "11" then
|
||||
zxn_cpu_speed2 <= zxn_cpu_speed;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
@@ -272,7 +272,7 @@ begin
|
||||
q0 <= not (zxn_cpu_speed(1) and zxn_cpu_speed(0)) and q0_enable when rising_edge(CLK_i0);
|
||||
q1 <= (zxn_cpu_speed(1) and zxn_cpu_speed(0)) and q1_enable when rising_edge(CLK_28);
|
||||
|
||||
CLK_CPU <= CLK_i0 when q0 = '1' else CLK_28 when q1 = '1' else '1';
|
||||
CLK_CPU <= CLK_i0 when q0 = '1' else CLK_28 when q1 = '1' else '1';
|
||||
|
||||
-- Clock Enables
|
||||
clk_28_div <= clk_28_div + 1 when rising_edge(CLK_28);
|
||||
|
||||
Reference in New Issue
Block a user