Files
TSConf_MiST/rtl/sound/gs.v
Eugene Lozovoy 66bfce85d5 add gs support
2024-09-14 16:41:57 +03:00

250 lines
7.3 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
-----------------------------------------------------------------------------
General Sound
-----------------------------------------------------------------------------
18.08.2018 Reworked first verilog version
19.08.2018 Produce proper signed output
20.08.2018 Use external SDR/DDR RAM for page 2 and up
21.05.2020 Use external SDR/DDR RAM for all ROM/RAM
CPU: Z80 @ 28MHz
ROM: 32K
RAM: up to 4096KB
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
(
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 [20:0] MEM_ADDR,
output [7:0] MEM_DI,
input [7:0] MEM_DO,
output MEM_RD,
output MEM_WR,
input MEM_WAIT,
output MEM_ROM,
output [14:0] OUTL,
output [14:0] OUTR
);
parameter INT_DIV = 291;
// port #xxBB : #xxB3
assign DO = A ? {flag_data, 6'b111111, flag_cmd} : 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;
T80pa CPU
(
.RESET_n(~RESET),
.CLK(CLK),
.CEN_p(CE & ~MEM_WAIT),
.INT_n(int_n),
.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 (RESET) begin
cnt <= 0;
int_n <= 1;
end else if(CE) begin
cnt <= cnt + 1'b1;
if (cnt == INT_DIV) begin // 37.48kHz
cnt <= 0;
int_n <= 0;
end
end
if (~cpu_iorq_n & ~cpu_m1_n) int_n <= 1;
end
reg flag_data;
reg flag_cmd;
always @(posedge CLK) begin
if (~cpu_iorq_n & cpu_m1_n) begin
case(cpu_a_bus[3:0])
'h2: flag_data <= 0;
'h3: flag_data <= 1;
'h5: flag_cmd <= 0;
'hA: flag_data <= ~port_00[0];
'hB: flag_cmd <= port_09[5];
endcase
end
if (~CS_n) begin
if (~A & ~RD_n) flag_data <= 0;
if (~A & ~WR_n) flag_data <= 1;
if ( A & ~WR_n) flag_cmd <= 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 [5: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[5: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 && ~MEM_WAIT) 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 && ~cpu_rd_n) ? MEM_DO :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 1) ? port_BB :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 2) ? port_B3 :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 4) ? {flag_data, 6'b111111, flag_cmd} :
8'hFF;
wire [5: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 = ~cpu_rd_n & ~cpu_mreq_n;
assign MEM_WR = ~cpu_wr_n & ~cpu_mreq_n & ~MEM_ROM;
assign MEM_DI = cpu_do_bus;
assign MEM_ROM = ~|page_addr;
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