Support for TZX.

This commit is contained in:
sorgelig
2021-04-09 02:20:08 +08:00
parent ea3b392b09
commit 941c65834e
6 changed files with 798 additions and 13 deletions

141
ZXNext.sv
View File

@@ -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

View File

@@ -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
View 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
View 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
View 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;

View File

@@ -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);