Improve General Sound. Use up to 4MB of RAM.

This commit is contained in:
sorgelig
2018-08-19 23:31:07 +08:00
parent 412901568b
commit 550ee59c7e
12 changed files with 1960 additions and 29466 deletions

View File

@ -374,7 +374,7 @@ set_global_assignment -name VHDL_FILE src/rtc/mc146818a.vhd
set_global_assignment -name VHDL_FILE src/sound/soundrive.vhd
set_global_assignment -name VHDL_FILE src/sound/turbosound.vhd
set_global_assignment -name VHDL_FILE src/sound/ay8910.vhd
set_global_assignment -name VHDL_FILE src/sound/gs.vhd
set_global_assignment -name VERILOG_FILE src/sound/gs.v
set_global_assignment -name SYSTEMVERILOG_FILE src/sound/saa1099.sv
set_global_assignment -name VERILOG_FILE src/memory/dma.v
set_global_assignment -name VERILOG_FILE src/memory/arbiter.v
@ -394,12 +394,13 @@ set_global_assignment -name VERILOG_FILE src/video/mem/video_sfile.v
set_global_assignment -name VERILOG_FILE src/video/mem/video_cram.v
set_global_assignment -name VERILOG_FILE src/video/video_top.v
set_global_assignment -name VHDL_FILE src/gen_rom.vhd
set_global_assignment -name VHDL_FILE src/gen_ram.vhd
set_global_assignment -name VHDL_FILE src/keyboard.vhd
set_global_assignment -name VERILOG_FILE src/kempston_mouse.v
set_global_assignment -name VERILOG_FILE src/spi.v
set_global_assignment -name VHDL_FILE src/sdram.vhd
set_global_assignment -name VERILOG_FILE src/clock.v
set_global_assignment -name VHDL_FILE src/tsconf.vhd
set_global_assignment -name SYSTEMVERILOG_FILE ddram.sv
set_global_assignment -name VERILOG_FILE dpram.v
set_global_assignment -name SYSTEMVERILOG_FILE TSConf.sv
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -357,7 +357,6 @@ set_location_assignment PIN_W21 -to SW[2]
set_location_assignment PIN_W20 -to SW[3]
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:sys/build_id.tcl"
set_global_assignment -name CDF_FILE jtag.cdf
set_global_assignment -name QIP_FILE sys/sys.qip
set_global_assignment -name QSYS_FILE sys/vip.qsys
@ -380,7 +379,7 @@ set_global_assignment -name VHDL_FILE src/rtc/mc146818a.vhd
set_global_assignment -name VHDL_FILE src/sound/soundrive.vhd
set_global_assignment -name VHDL_FILE src/sound/turbosound.vhd
set_global_assignment -name VHDL_FILE src/sound/ay8910.vhd
set_global_assignment -name VHDL_FILE src/sound/gs.vhd
set_global_assignment -name VERILOG_FILE src/sound/gs.v
set_global_assignment -name SYSTEMVERILOG_FILE src/sound/saa1099.sv
set_global_assignment -name VERILOG_FILE src/memory/dma.v
set_global_assignment -name VERILOG_FILE src/memory/arbiter.v
@ -400,12 +399,12 @@ set_global_assignment -name VERILOG_FILE src/video/mem/video_sfile.v
set_global_assignment -name VERILOG_FILE src/video/mem/video_cram.v
set_global_assignment -name VERILOG_FILE src/video/video_top.v
set_global_assignment -name VHDL_FILE src/gen_rom.vhd
set_global_assignment -name VHDL_FILE src/gen_ram.vhd
set_global_assignment -name VHDL_FILE src/keyboard.vhd
set_global_assignment -name VERILOG_FILE src/kempston_mouse.v
set_global_assignment -name VERILOG_FILE src/spi.v
set_global_assignment -name VHDL_FILE src/sdram.vhd
set_global_assignment -name VERILOG_FILE src/clock.v
set_global_assignment -name VHDL_FILE src/tsconf.vhd
set_global_assignment -name SYSTEMVERILOG_FILE TSConf.sv
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
set_global_assignment -name SYSTEMVERILOG_FILE ddram.sv
set_global_assignment -name VERILOG_FILE dpram.v
set_global_assignment -name SYSTEMVERILOG_FILE TSConf.svset_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -97,8 +97,6 @@ module emu
output SDRAM_nWE
);
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = '0;
assign LED_USER = vsd_sel & sd_act;
assign LED_DISK = {1'b1, ~vsd_sel & sd_act};
assign LED_POWER = 0;
@ -112,7 +110,7 @@ localparam CONF_STR = {
"O5,Aspect ratio,4:3,16:9;",
"O12,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;",
"O34,Stereo mix,None,25%,50%,100%;",
"OS,General Sound,Enabled,Disabled;",
"OST,General Sound,512KB,1MB,2MB,4MB;",
"-;",
"O67,CPU Speed,3.5MHz,7MHz,14MHz;",
"O8,CPU Cache,On,Off;",
@ -264,7 +262,13 @@ tsconf tsconf
.SD_CLK(sdclk),
.SD_CS_N(sdss),
.GS_ENA(~status[28]),
.GS_ENA(1),
.GS_ADDR(gs_mem_addr),
.GS_DI(gs_mem_din),
.GS_DO(gs_mem_dout | gs_mem_mask),
.GS_RD(gs_mem_rd),
.GS_WR(gs_mem_wr),
.GS_WAIT(~gs_mem_ready),
.SOUND_L(AUDIO_L),
.SOUND_R(AUDIO_R),
@ -280,7 +284,39 @@ tsconf tsconf
.joystick(joy_0[5:0] | joy_1[5:0])
);
assign AUDIO_S = 0;
assign DDRAM_CLK = clk_mem;
wire [21:0] gs_mem_addr;
wire [7:0] gs_mem_dout;
wire [7:0] gs_mem_din;
wire gs_mem_rd;
wire gs_mem_wr;
wire gs_mem_ready;
reg [7:0] gs_mem_mask;
always_comb begin
gs_mem_mask = 0;
case(status[29:28])
0: if(gs_mem_addr[21:19]) gs_mem_mask = 8'hFF;
1: if(gs_mem_addr[21:20]) gs_mem_mask = 8'hFF;
2: if(gs_mem_addr[21] ) gs_mem_mask = 8'hFF;
3: gs_mem_mask = 0;
endcase
end
ddram ddram
(
.*,
.addr(gs_mem_addr),
.dout(gs_mem_dout),
.din(gs_mem_din),
.we(gs_mem_wr),
.rd(gs_mem_rd),
.ready(gs_mem_ready)
);
assign AUDIO_S = 1;
assign AUDIO_MIX = status[4:3];
reg ce_pix;

124
ddram.sv Normal file
View File

@ -0,0 +1,124 @@
//
// ddram.v
//
// DE10-nano DDR3 memory interface
//
// Copyright (c) 2017 Sorgelig
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------
//
// 8-bit version
module ddram
(
input reset,
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:0] addr, // 256MB at the end of 1GB
output [7:0] dout, // data output to cpu
input [7:0] din, // data input from cpu
input we, // cpu requests write
input rd, // cpu requests read
output ready // dout is valid. Ready to accept new read/write.
);
assign DDRAM_BURSTCNT = 1;
assign DDRAM_BE = (8'd1<<ram_address[2:0]) | {8{ram_read}};
assign DDRAM_ADDR = {4'b0011, ram_address[27:3]}; // RAM at 0x30000000
assign DDRAM_RD = ram_read;
assign DDRAM_DIN = ram_cache;
assign DDRAM_WE = ram_write;
assign dout = ram_q;
assign ready = ~busy;
reg [7:0] ram_q;
reg [27:0] ram_address;
reg ram_read;
reg [63:0] ram_cache;
reg ram_write;
reg [7:0] cached;
reg busy;
always @(posedge DDRAM_CLK)
begin
reg old_rd, old_we;
reg old_reset;
reg state;
old_reset <= reset;
if(old_reset && ~reset) begin
busy <= 0;
state <= 0;
cached <= 0;
end
if(!DDRAM_BUSY)
begin
ram_write <= 0;
ram_read <= 0;
if(state) begin
if(DDRAM_DOUT_READY) begin
ram_q <= DDRAM_DOUT[{ram_address[2:0], 3'b000} +:8];
ram_cache <= DDRAM_DOUT;
cached <= 8'hFF;
state <= 0;
busy <= 0;
end
end
else begin
old_rd <= rd;
old_we <= we;
busy <= 0;
if(~old_we && we) begin
ram_cache[{addr[2:0], 3'b000} +:8] <= din;
ram_address <= addr;
busy <= 1;
ram_write <= 1;
cached <= ((ram_address[27:3] == addr[27:3]) ? cached : 8'h00) | (8'd1<<addr[2:0]);
end
if(~old_rd && rd) begin
if((ram_address[27:3] == addr[27:3]) && (cached & (8'd1<<addr[2:0]))) begin
ram_q <= ram_cache[{addr[2:0], 3'b000} +:8];
end
else begin
ram_address <= addr;
ram_read <= 1;
state <= 1;
cached <= 0;
busy <= 1;
end
end
end
end
end
endmodule

72
dpram.v Normal file
View File

@ -0,0 +1,72 @@
module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<<ADDRWIDTH, MEM_INIT_FILE="")
(
input clock,
input [ADDRWIDTH-1:0] address_a,
input [DATAWIDTH-1:0] data_a,
input wren_a,
output [DATAWIDTH-1:0] q_a,
input [ADDRWIDTH-1:0] address_b,
input [DATAWIDTH-1:0] data_b,
input wren_b,
output [DATAWIDTH-1:0] q_b
);
altsyncram altsyncram_component (
.address_a (address_a),
.address_b (address_b),
.clock0 (clock),
.data_a (data_a),
.data_b (data_b),
.wren_a (wren_a),
.wren_b (wren_b),
.q_a (q_a),
.q_b (q_b),
.aclr0 (1'b0),
.aclr1 (1'b0),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.eccstatus (),
.rden_a (1'b1),
.rden_b (1'b1));
defparam
altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0",
altsyncram_component.address_reg_b = "CLOCK0",
altsyncram_component.indata_reg_b = "CLOCK0",
altsyncram_component.numwords_a = NUMWORDS,
altsyncram_component.numwords_b = NUMWORDS,
altsyncram_component.widthad_a = ADDRWIDTH,
altsyncram_component.widthad_b = ADDRWIDTH,
altsyncram_component.width_a = DATAWIDTH,
altsyncram_component.width_b = DATAWIDTH,
altsyncram_component.width_byteena_a = 1,
altsyncram_component.width_byteena_b = 1,
altsyncram_component.init_file = MEM_INIT_FILE,
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_input_b = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.clock_enable_output_b = "BYPASS",
altsyncram_component.intended_device_family = "Cyclone V",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
altsyncram_component.outdata_aclr_a = "NONE",
altsyncram_component.outdata_aclr_b = "NONE",
altsyncram_component.outdata_reg_a = "UNREGISTERED",
altsyncram_component.outdata_reg_b = "UNREGISTERED",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ";
endmodule

View File

@ -1,84 +0,0 @@
-- -----------------------------------------------------------------------
--
-- Syntiac's generic VHDL support files.
--
-- -----------------------------------------------------------------------
-- Copyright 2005-2008 by Peter Wendrich (pwsoft@syntiac.com)
-- http://www.syntiac.com/fpga64.html
--
-- Modified April 2016 by Dar (darfpga@aol.fr)
-- http://darfpga.blogspot.fr
-- Remove address register when writing
--
-- -----------------------------------------------------------------------
--
-- gen_rwram.vhd
--
-- -----------------------------------------------------------------------
--
-- generic ram.
--
-- -----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
-- -----------------------------------------------------------------------
entity gen_ram is
generic (
dWidth : integer := 8;
aWidth : integer := 10
);
port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector((aWidth-1) downto 0);
d : in std_logic_vector((dWidth-1) downto 0);
q : out std_logic_vector((dWidth-1) downto 0)
);
end entity;
-- -----------------------------------------------------------------------
architecture rtl of gen_ram is
subtype addressRange is integer range 0 to ((2**aWidth)-1);
type ramDef is array(addressRange) of std_logic_vector((dWidth-1) downto 0);
signal ram: ramDef;
signal rAddrReg : std_logic_vector((aWidth-1) downto 0);
signal qReg : std_logic_vector((dWidth-1) downto 0);
begin
-- -----------------------------------------------------------------------
-- Signals to entity interface
-- -----------------------------------------------------------------------
-- q <= qReg;
-- -----------------------------------------------------------------------
-- Memory write
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(addr))) <= d;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Memory read
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
-- qReg <= ram(to_integer(unsigned(rAddrReg)));
-- rAddrReg <= addr;
---- qReg <= ram(to_integer(unsigned(addr)));
q <= ram(to_integer(unsigned(addr)));
end if;
end process;
--q <= ram(to_integer(unsigned(addr)));
end architecture;

255
src/sound/gs.v Normal file
View File

@ -0,0 +1,255 @@
/*
-----------------------------------------------------------------------------
General Sound
-----------------------------------------------------------------------------
18.08.2018 Reworked first verilog version
19.08.2018 Produce proper signed output
CPU: Z80 @ 28MHz
ROM: 32K
RAM: 128KB+
INT: 37.5KHz
#xxBB Command register - регистр команд, доступный для записи
#xxBB Status register - регистр состояния, доступный для чтения
bit 7 флаг данных
bit <6:1> Не определен
bit 0 флаг команд. Этот регистр позволяет определить состояние GS, в частности можно ли прочитать или записать очередной байт данных, или подать очередную команду, и т.п.
#xxB3 Data register - регистр данных, доступный для записи. В этот регистр Спектрум записывает данные, например, это могут быть аргументы команд.
#xxB3 Output register - регистр вывода, доступный для чтения. Из этого регистра Спектрум читает данные, идущие от GS
Внутренние порта:
#xx00 "расширенная память" - регистр доступный для записи
bit <3:0> переключают страницы по 32Kb, страница 0 - ПЗУ
bit <7:0> не используются
порты 1 - 5 "обеспечивают связь с SPECTRUM'ом"
#xx01 чтение команды General Sound'ом
bit <7:0> код команды
#xx02 чтение данных General Sound'ом
bit <7:0> данные
#xx03 запись данных General Sound'ом для SPECTRUM'a
bit <7:0> данные
#xx04 чтение слова состояния General Sound'ом
bit 0 флаг команд
bit 7 флаг данных
#xx05 сбрасывает бит D0 (флаг команд) слова состояния
порты 6 - 9 "регулировка громкости" в каналах 1 - 4
#xx06 "регулировка громкости" в канале 1
bit <5:0> громкость
bit <7:6> не используются
#xx07 "регулировка громкости" в канале 2
bit <5:0> громкость
bit <7:6> не используются
#xx08 "регулировка громкости" в канале 3
bit <5:0> громкость
bit <7:6> не используются
#xx09 "регулировка громкости" в канале 4
bit <5:0> громкость
bit <7:6> не используются
#xx0A устанавливает бит 7 слова состояния не равным биту 0 порта #xx00
#xx0B устанавливает бит 0 слова состояния равным биту 5 порта #xx06
Распределение памяти
#0000 - #3FFF - первые 16Kb ПЗУ
#4000 - #7FFF - первые 16Kb первой страницы ОЗУ
#8000 - #FFFF - листаемые страницы по 32Kb
страница 0 - ПЗУ,
страница 1 - первая страница ОЗУ
страницы 2... ОЗУ
Данные в каналы заносятся при чтении процессором ОЗУ по адресам #6000 - #7FFF автоматически.
*/
module gs #(parameter PAGES=4, ROMFILE="gs105b.mif")
(
input RESET,
input CLK,
input CE,
input A,
input [7:0] DI,
output [7:0] DO,
input CS_n,
input WR_n,
input RD_n,
output [21:0] MEM_ADDR,
output [7:0] MEM_DI,
input [7:0] MEM_DO,
output MEM_RD,
output MEM_WR,
input MEM_WAIT,
output [14:0] OUTL,
output [14:0] OUTR
);
// port #xxBB : #xxB3
assign DO = A ? {bit7, 6'b111111, bit0} : port_03;
// CPU
reg int_n;
wire cpu_m1_n;
wire cpu_mreq_n;
wire cpu_iorq_n;
wire cpu_rd_n;
wire cpu_wr_n;
wire [15:0] cpu_a_bus;
wire [7:0] cpu_do_bus;
T80s cpu
(
.RESET_n(~RESET),
.CLK_n(CLK),
.CEN(CE & ~MEM_WAIT),
.WAIT_n(1),
.INT_n(int_n),
.NMI_n(1),
.BUSRQ_n(1),
.M1_n(cpu_m1_n),
.MREQ_n(cpu_mreq_n),
.IORQ_n(cpu_iorq_n),
.RD_n(cpu_rd_n),
.WR_n(cpu_wr_n),
.A(cpu_a_bus),
.DO(cpu_do_bus),
.DI(cpu_di_bus)
);
// INT#
always @(posedge CLK) begin
reg [9:0] cnt;
if(CE) begin
cnt <= cnt + 1'b1;
if (cnt == 746) begin // 37.48kHz
cnt <= 0;
int_n <= 0;
end
end
if (~cpu_iorq_n & ~cpu_m1_n) int_n <= 1;
end
reg bit7;
reg bit0;
always @(posedge CLK) begin
if (~cpu_iorq_n & cpu_m1_n) begin
case(cpu_a_bus[3:0])
'h2: bit7 <= 0;
'h3: bit7 <= 1;
'h5: bit0 <= 0;
'hA: bit7 <= ~port_00[0];
'hB: bit0 <= port_09[5];
endcase
end
else if (~CS_n) begin
if (~A & ~RD_n) bit7 <= 0;
if (~A & ~WR_n) bit7 <= 1;
if ( A & ~WR_n) bit0 <= 1;
end
end
reg [7:0] port_BB;
reg [7:0] port_B3;
always @(posedge CLK) begin
if (RESET) begin
port_BB <= 0;
port_B3 <= 0;
end
else if (~CS_n && ~WR_n) begin
if(A) port_BB <= DI;
else port_B3 <= DI;
end
end
reg [6:0] port_00;
reg [7:0] port_03;
reg signed [6:0] port_06, port_07, port_08, port_09;
reg signed [7:0] ch_a, ch_b, ch_c, ch_d;
always @(posedge CLK) begin
if (RESET) begin
port_00 <= 0;
port_03 <= 0;
end
else begin
if (~cpu_iorq_n & ~cpu_wr_n) begin
case(cpu_a_bus[3:0])
0: port_00 <= cpu_do_bus[6:0];
3: port_03 <= cpu_do_bus;
6: port_06 <= cpu_do_bus[5:0];
7: port_07 <= cpu_do_bus[5:0];
8: port_08 <= cpu_do_bus[5:0];
9: port_09 <= cpu_do_bus[5:0];
endcase
end
if (~cpu_mreq_n && ~cpu_rd_n && cpu_a_bus[15:13] == 3) begin
case(cpu_a_bus[9:8])
0: ch_a <= {~mem_do[7],mem_do[6:0]};
1: ch_b <= {~mem_do[7],mem_do[6:0]};
2: ch_c <= {~mem_do[7],mem_do[6:0]};
3: ch_d <= {~mem_do[7],mem_do[6:0]};
endcase
end
end
end
wire [7:0] cpu_di_bus =
(~cpu_mreq_n && !page_addr[6:1]) ? mem_do :
(~cpu_mreq_n) ? MEM_DO :
(~cpu_iorq_n && cpu_a_bus[3:0] == 1) ? port_BB :
(~cpu_iorq_n && cpu_a_bus[3:0] == 2) ? port_B3 :
(~cpu_iorq_n && cpu_a_bus[3:0] == 4) ? {bit7, 6'b111111, bit0} :
8'hFF;
wire mem_wr = ~cpu_wr_n & ~cpu_mreq_n & |page_addr;
wire mem_rd = ~cpu_rd_n & ~cpu_mreq_n;
wire [6:0] page_addr = cpu_a_bus[15] ? port_00 : cpu_a_bus[14];
assign MEM_ADDR = {page_addr, &cpu_a_bus[15:14], cpu_a_bus[13:0]};
assign MEM_RD = mem_rd && |page_addr[6:1];
assign MEM_WR = mem_wr && |page_addr[6:1];
assign MEM_DI = cpu_do_bus;
wire [7:0] mem_do;
dpram #(.ADDRWIDTH(16), .NUMWORDS(2*32768), .MEM_INIT_FILE(ROMFILE)) mem
(
.clock(CLK),
.address_a(MEM_ADDR[15:0]),
.wren_a(mem_wr && !page_addr[6:1]),
.data_a(cpu_do_bus),
.q_a(mem_do)
);
reg signed [14:0] out_a,out_b,out_c,out_d;
always @(posedge CLK) begin
if(CE) begin
out_a <= ch_a * port_06;
out_b <= ch_b * port_07;
out_c <= ch_c * port_08;
out_d <= ch_d * port_09;
end
end
reg signed [14:0] outl, outr;
always @(posedge CLK) begin
if(CE) begin
outl <= out_a + out_b;
outr <= out_c + out_d;
end
end
assign OUTL = outl;
assign OUTR = outr;
endmodule

View File

@ -1,329 +0,0 @@
-------------------------------------------------------------------[04.10.2015]
-- General Sound
-------------------------------------------------------------------------------
-- 01.11.2011 первая версия
-- 19.12.2011 CPU @ 84MHz, подтверждение INT#
-- 10.05.2013 исправлен bit7_flag, bit0_flag
-- 29.05.2013 добавлена громкость каналов, CPU @ 21MHz
-- 21.07.2013 исправлен int_n
-- CPU: Z80
-- ROM: 32K
-- RAM: 384K
-- INT: 37.5KHz
-- #xxBB Command register - регистр команд, доступный для записи
-- #xxBB Status register - регистр состояния, доступный для чтения
-- bit 7 флаг данных
-- bit <6:1> Не определен
-- bit 0 флаг команд. Этот регистр позволяет определить состояние GS, в частности можно ли прочитать или записать очередной байт данных, или подать очередную команду, и т.п.
-- #xxB3 Data register - регистр данных, доступный для записи. В этот регистр Спектрум записывает данные, например, это могут быть аргументы команд.
-- #xxB3 Output register - регистр вывода, доступный для чтения. Из этого регистра Спектрум читает данные, идущие от GS
-- Внутренние порта:
-- #xx00 "расширенная память" - регистр доступный для записи
-- bit <3:0> переключают страницы по 32Kb, страница 0 - ПЗУ
-- bit <7:0> не используются
-- порты 1 - 5 "обеспечивают связь с SPECTRUM'ом"
-- #xx01 чтение команды General Sound'ом
-- bit <7:0> код команды
-- #xx02 чтение данных General Sound'ом
-- bit <7:0> данные
-- #xx03 запись данных General Sound'ом для SPECTRUM'a
-- bit <7:0> данные
-- #xx04 чтение слова состояния General Sound'ом
-- bit 0 флаг команд
-- bit 7 флаг данных
-- #xx05 сбрасывает бит D0 (флаг команд) слова состояния
-- порты 6 - 9 "регулировка громкости" в каналах 1 - 4
-- #xx06 "регулировка громкости" в канале 1
-- bit <5:0> громкость
-- bit <7:6> не используются
-- #xx07 "регулировка громкости" в канале 2
-- bit <5:0> громкость
-- bit <7:6> не используются
-- #xx08 "регулировка громкости" в канале 3
-- bit <5:0> громкость
-- bit <7:6> не используются
-- #xx09 "регулировка громкости" в канале 4
-- bit <5:0> громкость
-- bit <7:6> не используются
-- #xx0A устанавливает бит 7 слова состояния не равным биту 0 порта #xx00
-- #xx0B устанавливает бит 0 слова состояния равным биту 5 порта #xx06
--Распределение памяти
--#0000 - #3FFF - первые 16Kb ПЗУ
--#4000 - #7FFF - первые 16Kb первой страницы ОЗУ
--#8000 - #FFFF - листаемые страницы по 32Kb
-- страница 0 - ПЗУ,
-- страница 1 - первая страница ОЗУ
-- страницы 2... ОЗУ
--Данные в каналы заносятся при чтении процессором ОЗУ по адресам #6000 - #7FFF автоматически.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.all;
entity gs is
Port (
RESET : in std_logic;
CLK : in std_logic;
CE : in std_logic;
A : in std_logic_vector(15 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
WR_n : in std_logic;
RD_n : in std_logic;
IORQ_n : in std_logic;
M1_n : in std_logic;
OUTL : out std_logic_vector(14 downto 0);
OUTR : out std_logic_vector(14 downto 0)
);
end gs;
architecture gs_unit of gs is
signal port_xxbb_reg : std_logic_vector(7 downto 0);
signal port_xxb3_reg : std_logic_vector(7 downto 0);
signal port_xx00_reg : std_logic_vector(7 downto 0);
signal port_xx03_reg : std_logic_vector(7 downto 0);
signal port_xx06_reg : std_logic_vector(5 downto 0);
signal port_xx07_reg : std_logic_vector(5 downto 0);
signal port_xx08_reg : std_logic_vector(5 downto 0);
signal port_xx09_reg : std_logic_vector(5 downto 0);
signal ch_a_reg : std_logic_vector(7 downto 0);
signal ch_b_reg : std_logic_vector(7 downto 0);
signal ch_c_reg : std_logic_vector(7 downto 0);
signal ch_d_reg : std_logic_vector(7 downto 0);
signal bit7_flag : std_logic;
signal bit0_flag : std_logic;
signal cnt : std_logic_vector(9 downto 0);
signal int_n : std_logic;
signal out_a : std_logic_vector(13 downto 0);
signal out_b : std_logic_vector(13 downto 0);
signal out_c : std_logic_vector(13 downto 0);
signal out_d : std_logic_vector(13 downto 0);
-- CPU
signal cpu_m1_n : std_logic;
signal cpu_mreq_n : std_logic;
signal cpu_iorq_n : std_logic;
signal cpu_rd_n : std_logic;
signal cpu_wr_n : std_logic;
signal cpu_a_bus : std_logic_vector(15 downto 0);
signal cpu_di_bus : std_logic_vector(7 downto 0);
signal cpu_do_bus : std_logic_vector(7 downto 0);
signal ram_we : std_logic;
signal ram_en : std_logic;
signal rom_do : std_logic_vector(7 downto 0);
signal ram1_do : std_logic_vector(7 downto 0);
signal ram2_do : std_logic_vector(7 downto 0);
signal mem_do : std_logic_vector(7 downto 0);
signal ram_addr : std_logic_vector(18 downto 0);
begin
z80_unit: entity work.T80s
generic map (
Mode => 0, -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
T2Write => 1, -- 0 => WR_n active in T3, 1 => WR_n active in T2
IOWait => 1) -- 0 => Single cycle I/O, 1 => Std I/O cycle
port map (
RESET_n => not RESET,
CLK_n => CLK,
CEN => CE,
WAIT_n => '1',
INT_n => int_n,
NMI_n => '1',
BUSRQ_n => '1',
M1_n => cpu_m1_n,
MREQ_n => cpu_mreq_n,
IORQ_n => cpu_iorq_n,
RD_n => cpu_rd_n,
WR_n => cpu_wr_n,
A => cpu_a_bus,
DI => cpu_di_bus,
DO => cpu_do_bus);
-- INT#
process (CLK)
begin
if rising_edge(CLK) then
if CE = '1' then
cnt <= cnt + 1;
if cnt = "1011101010" then -- 28MHz / 747 = 0.03748MHz = 37.48kHz
cnt <= (others => '0');
int_n <= '0';
end if;
if cpu_iorq_n = '0' and cpu_m1_n = '0' then
int_n <= '1';
end if;
end if;
end if;
end process;
process (CLK)
begin
if rising_edge(CLK) then
if (cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(3 downto 0) = X"2") or (IORQ_n = '0' and RD_n = '0' and A(7 downto 0) = X"B3") then
bit7_flag <= '0';
elsif (cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(3 downto 0) = X"3") or (IORQ_n = '0' and WR_n = '0' and A(7 downto 0) = X"B3") then
bit7_flag <= '1';
elsif (cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(3 downto 0) = X"A") then
bit7_flag <= not port_xx00_reg(0);
end if;
end if;
end process;
process (CLK)
begin
if rising_edge(CLK) then
if cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(3 downto 0) = X"5" then
bit0_flag <= '0';
elsif IORQ_n = '0' and WR_n = '0' and A(7 downto 0) = X"BB" then
bit0_flag <= '1';
elsif cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(3 downto 0) = X"B" then
bit0_flag <= port_xx09_reg(5);
end if;
end if;
end process;
process (CLK)
begin
-- запись со стороны спектрума
if rising_edge(CLK) then
if RESET = '1' then
port_xxbb_reg <= (others => '0');
port_xxb3_reg <= (others => '0');
else
if IORQ_n = '0' and WR_n = '0' and A(7 downto 0) = X"BB" then port_xxbb_reg <= DI; end if;
if IORQ_n = '0' and WR_n = '0' and A(7 downto 0) = X"B3" then port_xxb3_reg <= DI; end if;
end if;
end if;
end process;
-- port #xxBB / #xxB3
DO <= bit7_flag & "111111" & bit0_flag when A(3) = '1' else port_xx03_reg;
process (CLK)
begin
if rising_edge(CLK) then
if RESET = '1' then
port_xx00_reg <= (others => '0');
port_xx03_reg <= (others => '0');
port_xx06_reg <= (others => '0');
port_xx07_reg <= (others => '0');
port_xx08_reg <= (others => '0');
port_xx09_reg <= (others => '0');
ch_a_reg <= (others => '0');
ch_b_reg <= (others => '0');
ch_c_reg <= (others => '0');
ch_d_reg <= (others => '0');
elsif CE = '1' then
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"0" then port_xx00_reg <= cpu_do_bus; end if;
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"3" then port_xx03_reg <= cpu_do_bus; end if;
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"6" then port_xx06_reg <= cpu_do_bus(5 downto 0); end if;
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"7" then port_xx07_reg <= cpu_do_bus(5 downto 0); end if;
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"8" then port_xx08_reg <= cpu_do_bus(5 downto 0); end if;
if cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(3 downto 0) = X"9" then port_xx09_reg <= cpu_do_bus(5 downto 0); end if;
if cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(15 downto 13) = "011" and cpu_a_bus(9 downto 8) = "00" then ch_a_reg <= ram1_do; end if;
if cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(15 downto 13) = "011" and cpu_a_bus(9 downto 8) = "01" then ch_b_reg <= ram1_do; end if;
if cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(15 downto 13) = "011" and cpu_a_bus(9 downto 8) = "10" then ch_c_reg <= ram1_do; end if;
if cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(15 downto 13) = "011" and cpu_a_bus(9 downto 8) = "11" then ch_d_reg <= ram1_do; end if;
end if;
end if;
end process;
-- Шина данных CPU
cpu_di_bus <=
mem_do when (cpu_mreq_n = '0' and cpu_rd_n = '0') else
bit7_flag & "111111" & bit0_flag when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(3 downto 0) = X"4") else
port_xxbb_reg when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(3 downto 0) = X"1") else
port_xxb3_reg when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(3 downto 0) = X"2") else
"11111111";
ram_en <= '1' when cpu_a_bus(15 downto 14) = "01" or (cpu_a_bus(15) = '1' and port_xx00_reg(3 downto 0) /= "0000") else '0';
ram_we <= not cpu_wr_n and not cpu_mreq_n and ram_en;
ram_addr <=
"00000" & cpu_a_bus(13 downto 0) when cpu_a_bus(15) = '0' else
(port_xx00_reg(3 downto 0) - "0001") & cpu_a_bus(14 downto 0);
mem_do <=
rom_do when ram_en = '0' else
ram1_do when cpu_a_bus(15 downto 14) = "01" or (cpu_a_bus(15) = '1' and port_xx00_reg(3 downto 0) /= "0000" and ram_addr(18) = '0') else
ram2_do when cpu_a_bus(15) = '1' and port_xx00_reg(3 downto 0) /= "0000" and ram_addr(18 downto 17) = "10" else
x"FF";
ROM: entity work.gen_rom
generic map
(
INIT_FILE => "src/sound/gs105a.mif ",
ADDR_WIDTH => 15
)
port map
(
wrclock => CLK,
rdclock => CLK,
rdaddress => cpu_a_bus(14 downto 0),
q => rom_do
);
-- 256KB
RAM1: entity work.gen_ram
generic map (
aWidth => 18
)
port map
(
clk => CLK,
we => ram_we and not ram_addr(18),
addr => ram_addr(17 downto 0),
d => cpu_do_bus,
q => ram1_do
);
-- 128KB
RAM2: entity work.gen_ram
generic map (
aWidth => 17
)
port map
(
clk => CLK,
we => ram_we and ram_addr(18) and not ram_addr(17),
addr => ram_addr(16 downto 0),
d => cpu_do_bus,
q => ram2_do
);
process (CLK)
begin
if rising_edge(CLK) then
if CE = '1' then
out_a <= ch_a_reg * port_xx06_reg;
out_b <= ch_b_reg * port_xx07_reg;
out_c <= ch_c_reg * port_xx08_reg;
out_d <= ch_d_reg * port_xx09_reg;
end if;
end if;
end process;
process (CLK)
begin
if rising_edge(CLK) then
if CE = '1' then
OUTL <= ('0'&out_a) + ('0'&out_b);
OUTR <= ('0'&out_c) + ('0'&out_d);
end if;
end if;
end process;
end gs_unit;

File diff suppressed because it is too large Load Diff

Binary file not shown.

1382
src/sound/gs105b.mif Normal file

File diff suppressed because it is too large Load Diff

View File

@ -92,8 +92,16 @@ port
SD_CLK : out std_logic;
SD_CS_N : out std_logic;
-- Audio
-- General Sound
GS_ENA : in std_logic;
GS_ADDR : out std_logic_vector(21 downto 0);
GS_DI : out std_logic_vector(7 downto 0);
GS_DO : in std_logic_vector(7 downto 0);
GS_RD : out std_logic;
GS_WR : out std_logic;
GS_WAIT : in std_logic;
-- Audio
SOUND_L : out std_logic_vector(15 downto 0);
SOUND_R : out std_logic_vector(15 downto 0);
@ -349,6 +357,9 @@ signal mouse_do : std_logic_vector(7 downto 0);
signal gs_l : std_logic_vector(14 downto 0);
signal gs_r : std_logic_vector(14 downto 0);
signal gs_do_bus : std_logic_vector(7 downto 0);
signal gs_sel : std_logic;
signal ce_gs : std_logic;
-- SAA1099
signal saa_wr_n : std_logic;
@ -818,6 +829,36 @@ port (
out_r : out std_logic_vector(7 downto 0));
end component;
component gs
generic (
PAGES : integer;
ROMFILE : string
);
port
(
RESET : in std_logic;
CLK : in std_logic;
CE : in std_logic;
A : in std_logic;
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
CS_n : in std_logic;
WR_n : in std_logic;
RD_n : in std_logic;
MEM_ADDR : out std_logic_vector(21 downto 0);
MEM_DI : out std_logic_vector(7 downto 0);
MEM_DO : in std_logic_vector(7 downto 0);
MEM_RD : out std_logic;
MEM_WR : out std_logic;
MEM_WAIT : in std_logic;
OUTL : out std_logic_vector(14 downto 0);
OUTR : out std_logic_vector(14 downto 0)
);
end component;
-------------------------------------------------------------------------------
begin
@ -1382,18 +1423,42 @@ port map (
CN1_B => ssg_cn1_b,
CN1_C => ssg_cn1_c);
U15: entity work.gs
process (clk_84mhz)
begin
if rising_edge(clk_84mhz) then
ce_gs <= clk_28mhz;
if ce_gs = '1' then
ce_gs <= '0';
end if;
end if;
end process;
U15: gs
generic map
(
PAGES => 4,
ROMFILE => "src/sound/gs105b.mif"
)
port map (
RESET => reset or not GS_ENA,
CLK => clk_28mhz,
CE => '1',
A => cpu_a_bus,
RESET => reset,
CLK => clk_84mhz,
CE => ce_gs,
A => cpu_a_bus(3),
DI => cpu_do_bus,
DO => gs_do_bus,
CS_n => cpu_iorq_n or not gs_sel,
WR_n => cpu_wr_n,
RD_n => cpu_rd_n,
IORQ_n => cpu_iorq_n,
M1_n => cpu_m1_n,
MEM_ADDR => GS_ADDR,
MEM_DI => GS_DI,
MEM_DO => GS_DO,
MEM_RD => GS_RD,
MEM_WR => GS_WR,
MEM_WAIT => GS_WAIT,
OUTL => gs_l,
OUTR => gs_r);
@ -1431,12 +1496,14 @@ cpu_addr_ext <= "100" when (loader = '1' and (cpu_a_bus(15 downto 14) = "10" or
dram_rdata <= sdr_do_bus_16;
gs_sel <= '1' when GS_ENA = '1' and cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_a_bus(7 downto 4) = "1011" and cpu_a_bus(2 downto 0) = "011" else '0';
cpu_di_bus <=
rom_do_bus when (loader = '1' and cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(15 downto 13) = "000") else -- loader ROM
sdr_do_bus when (cpu_mreq_n = '0' and cpu_rd_n = '0') else -- SDRAM
im2vect when intack = '1' else
mc146818a_do_bus when (cpu_iorq_n = '0' and cpu_rd_n = '0' and port_bff7 = '1' and port_eff7_reg(7) = '1') else -- MC146818A
gs_do_bus when (GS_ENA = '1' and cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus(7 downto 4) = "1011" and cpu_a_bus(2 downto 0) = "011") else -- General Sound
gs_do_bus when gs_sel='1' and cpu_rd_n = '0' else -- General Sound
ssg_cn0_bus when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus = "1111111111111101" and ssg_sel = '0') else -- TurboSound
ssg_cn1_bus when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus = "1111111111111101" and ssg_sel = '1') else
key_scancode when (cpu_iorq_n = '0' and cpu_rd_n = '0' and cpu_a_bus = X"0001") else
@ -1480,7 +1547,7 @@ SD_CS_N <= sdcs_n_TS;
-- SAA1099
saa_wr_n <= '0' when (cpu_iorq_n = '0' and cpu_wr_n = '0' and cpu_a_bus(7 downto 0) = "11111111" and dos = '0') else '1';
SOUND_L <= ("000" & port_xxfe_reg(4) & "000000000000") + ("000" & ssg_cn0_a & "00000") + ("0000" & ssg_cn0_b & "0000") + ("000" & ssg_cn1_a & "00000") + ("0000" & ssg_cn1_b & "0000") + ("00" & covox_a & "000000") + ("00" & covox_b & "000000") + ("0" & gs_l) + ("0" & saa_out_l & "0000000");
SOUND_R <= ("000" & port_xxfe_reg(4) & "000000000000") + ("000" & ssg_cn0_c & "00000") + ("0000" & ssg_cn0_b & "0000") + ("000" & ssg_cn1_c & "00000") + ("0000" & ssg_cn1_b & "0000") + ("00" & covox_c & "000000") + ("00" & covox_d & "000000") + ("0" & gs_r) + ("0" & saa_out_r & "0000000");
SOUND_L <= ("000" & port_xxfe_reg(4) & "000000000000") + ("000" & ssg_cn0_a & "00000") + ("0000" & ssg_cn0_b & "0000") + ("000" & ssg_cn1_a & "00000") + ("0000" & ssg_cn1_b & "0000") + ("00" & covox_a & "000000") + ("00" & covox_b & "000000") + (gs_l(14) & gs_l) + ("0" & saa_out_l & "0000000");
SOUND_R <= ("000" & port_xxfe_reg(4) & "000000000000") + ("000" & ssg_cn0_c & "00000") + ("0000" & ssg_cn0_b & "0000") + ("000" & ssg_cn1_c & "00000") + ("0000" & ssg_cn1_b & "0000") + ("00" & covox_c & "000000") + ("00" & covox_d & "000000") + (gs_r(14) & gs_r) + ("0" & saa_out_r & "0000000");
end rtl;