mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-19 07:11:22 +03:00
250 lines
7.3 KiB
Verilog
250 lines
7.3 KiB
Verilog
/*
|
||
|
||
-----------------------------------------------------------------------------
|
||
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
|