PDA

Просмотр полной версии : AY-3-8910 in FPGA



VELESOFT
16.02.2010, 00:09
http://alexfreed.com/FPGApple/DE1_ZX/ay-8910.v

psb
16.02.2010, 08:51
I'm not sure, but...

// tone generator
cnt_a <= cnt_a + 1;
if(cnt_a==period_a) <-----
begin
out_a <= ~out_a;
cnt_a <= 0;
end

Is this correct? If next loaded period will be less than current cnt_a value, then cnt_a will count to maximum. Does real ay have this feature?

May be there need some shadow registers for period_a, etc... ?

balu_dark
17.02.2010, 00:51
if(cnt_a==period_a) <-----
begin
out_a <= ~out_a;
cnt_a <= 0;
end

а чем тебе код не понравился? все правильно -код внутри бегина будет выполнятся только в конце периода - будет менять состояние вывода на противоположное и сбрасывть счетчик этого самого периода. что именно тут тебе не понравилосЬ? тем более это код из работающего проекта.

psb
17.02.2010, 08:03
мне не понравилось то, что само значение period_a может быть поменяно в любой момент. представь, что оно было 512. счетчик досчитал только до 300, а программер вбил новое значение period_a=256. тогда счетчик будет считать аж до 4095. не думаю что это правильно и хорошо.
я же предлагаю сделать доп. регистр period_a_, который обновлять только в конце периода. либо, на самый крайний случай, поставить не ==, а >=.

тем более это код из работающего проекта.
тем более;))) не спорю, да, пищать и шипеть он будет:)

molodcov_alex
17.02.2010, 11:14
Пожалуйте кусочек анрила:

if (++ta >= fa) ta = 0, bitA ^= -1;
if (++tb >= fb) tb = 0, bitB ^= -1;
if (++tc >= fc) tc = 0, bitC ^= -1;
И кусочек эмулятора Бульбы:

inc(Ton_Counter_A.Hi);
if Ton_Counter_A.Hi >= RegisterAY.TonA then
begin
Ton_Counter_A.Hi := 0;
Ton_A := Ton_A xor 1
end;
inc(Ton_Counter_B.Hi);
if Ton_Counter_B.Hi >= RegisterAY.TonB then
begin
Ton_Counter_B.Hi := 0;
Ton_B := Ton_B xor 1
end;
inc(Ton_Counter_C.Hi);
if Ton_Counter_C.Hi >= RegisterAY.TonC then
begin
Ton_Counter_C.Hi := 0;
Ton_C := Ton_C xor 1
end;

psb
17.02.2010, 11:37
ну вот, так правильнее. если не теневой регистр (хз как по правде надо), то хотя бы сравнение не жесткое:)

balu_dark
17.02.2010, 15:37
либо, на самый крайний случай, поставить не ==, а >=.

тем более;))) не спорю, да, пищать и шипеть он будет:)

ну теперь то я тебя понял :)

syd
24.03.2010, 21:51
Есть еще реализация от MikeJ на VHDL тут http://www.fpgaarcade.com/library.htm (точнее две реализации). Так вот, у меня почему-то музыка из Treasure Island Dizzy на всех этих трех реализациях играет не корректно, слышно только шум. Кто-то может это проверить у себя. Или намекнуть, чем эта музыка отличается от остальных.

bigral
25.03.2010, 00:17
Так вот, у меня почему-то музыка из Treasure Island Dizzy на всех этих трех реализациях играет не корректно, слышно только шум. Кто-то может это проверить у себя. Или намекнуть, чем эта музыка отличается от остальных.

Странно, неужели абсолютно идентичные сигналы на выходе у всех реализаций? Это наталкивает на мысль о том что какая-то часть схемы содрана у всех реализаций с одной. Возможно в самой схеме подключения AY-ка существует проблема и какая нибудь хакерская схема адресации AY-ка в этой Treasure Island Dizzy используется.

syd
25.03.2010, 00:34
Сигналы на выходе просто похожи, не идентичны. Возможно глюк у меня в схеме, по-этому и прошу проверить. Во всех остальных играх, которые смотрел, все ок.

syd
26.03.2010, 01:04
Бага в T80 :v2_jawdr:. Инструкция OUTD не уменьшала HL. Теперь все ок.

balu_dark
26.03.2010, 01:23
покажи демо платку хоть ;)

serkiri
10.04.2010, 21:50
А нельзя ли выложить примеры

Vslav
22.12.2015, 18:34
Прикольно, а ЦАП в AY-3-8910 очень похож на 7-битный:

http://s015.radikal.ru/i330/1512/0b/67b02ad6bbdct.jpg (http://s015.radikal.ru/i330/1512/0b/67b02ad6bbdc.jpg)

Желтыми линиями обозначены каналы транзисторов, подключены параллельно. Длиннее канал - больше сопротивление.

HardWareMan
22.12.2015, 19:25
Так у него весовой ЦАП? Я думал там резисторный (где-то видел картинку с 16тью сопротивлениями и дешифратором 4-к-16).

Vslav
22.12.2015, 20:08
Так у него весовой ЦАП? Я думал там резисторный (где-то видел картинку с 16тью сопротивлениями и дешифратором 4-к-16).
Оказалось что вот те квадратики слева - это еще 8 транзисторов с разными сопротивлениями каналов. Итого - 15 штук на канал. Получается 16 уровней (16-ый - когда все транзисторы закрыты, внешний резистор утягивает значение на "землю"), что соответствует 4-битному значению. А жаль, так красиво все на картинке сначала было :)

HardWareMan
23.12.2015, 10:50
Ну вот, я так и думал. Старшие разряды толще потому как ток выше, это и понятно. А те 8 это младшие. Стало быть тут все так же 4-к-16.

Tronix
25.12.2015, 20:55
А в EPM7064 влезет, хотя еще лучше в 3032 -))
А по теме - выложите плиз исходники, все ссылки битые.

zebest
25.12.2015, 22:13
все ссылки битые.


ay-8910.v

// ports are not identical to the actual AY chip - no need for that.
// Also the parallel ports are not very useful, so they are not connected




module ay8910(rst_n,clk,clk_en,asel,wr_n,cs_n,di,do,A,B,C );
input rst_n;
input clk; // 28 MHz clock from the system
input clk_en; // 1.7 (?) clock to run the sound timing
input asel;
input wr_n;
input cs_n;
input [7:0] di;
output [7:0] do;
output [7:0] A;
output [7:0] B;
output [7:0] C;




/////////////////////////////////////////////////////////////////////////////
// Write Register
/////////////////////////////////////////////////////////////////////////////


reg [3:0] addr;


// registers
reg [11:0] period_a,period_b,period_c;
reg [4:0] period_n;
reg [7:0] reg_en;
reg [4:0] vol_a,vol_b,vol_c;
reg [15:0] period_e;
reg [3:0] shape_e;
reg [7:0] pa_r,pb_r;


wire pb_od = reg_en[7];
wire pa_od = reg_en[6];
wire na = reg_en[5];
wire nb = reg_en[4];
wire nc = reg_en[3];
wire ena = reg_en[2];
wire enb = reg_en[1];
wire enc = reg_en[0];


always @(posedge clk)
if(~rst_n) begin
vol_a <= 0;
vol_b <= 0;
vol_c <= 0;
end else


if(~wr_n && ~cs_n) begin
if(asel)
begin
// address write
addr <= di[3:0];
end else begin
// register write
case(addr)
0:period_a[ 7:0] <= di;
1:period_a[11:8] <= di[3:0];
2:period_b[ 7:0] <= di;
3:period_b[11:8] <= di[3:0];
4:period_c[ 7:0] <= di;
5:period_c[11:8] <= di[3:0];
6:period_n[ 4:0] <= di[4:0];
7:reg_en <= di;
8:vol_a <= di[4:0];
9:vol_b <= di[4:0];
10:vol_c <= di[4:0];
11:period_e[7:0] <= di;
12:period_e[15:8] <= di;
13:shape_e <= di[3:0];
14:pa_r <= di;
15:pb_r <= di;
endcase
end
end


/////////////////////////////////////////////////////////////////////////////
// Read Register
/////////////////////////////////////////////////////////////////////////////
assign do = addr==4'h0 ? period_a[7:0] :
addr==4'h1 ? {4'h0,period_a[11:0]} :
addr==4'h2 ? period_b[7:0] :
addr==4'h3 ? {4'h0,period_b[11:0]} :
addr==4'h4 ? period_c[7:0] :
addr==4'h5 ? {4'h0,period_c[11:0]} :
addr==4'h6 ? {3'h0,period_n} :
addr==4'h7 ? reg_en :
addr==4'h8 ? {3'h0,vol_a} :
addr==4'h9 ? {3'h0,vol_b} :
addr==4'ha ? {3'h0,vol_c} :
addr==4'hb ? period_e[7:0] :
addr==4'hc ? period_e[15:8] :
addr==4'hd ? {4'h0,shape_e} : 8'hff;



/////////////////////////////////////////////////////////////////////////////
// PSG
/////////////////////////////////////////////////////////////////////////////


//
// toneA 12bit | 12bit
// toneB 12bit | 12bit
// toneC 12bit | 12bit
// env 15bit | 15bit
//
reg [2:0] pris;
reg [11:0] cnt_a,cnt_b,cnt_c;


reg out_a,out_b,out_c;


always @(posedge clk)
if(clk_en) begin
pris <= pris + 1;
if(pris==0)
begin
// tone generator
cnt_a <= cnt_a + 1;
if(cnt_a==period_a)
begin
out_a <= ~out_a;
cnt_a <= 0;
end
cnt_b <= cnt_b + 1;
if(cnt_b==period_b)
begin
out_b <= ~out_b;
cnt_b <= 0;
end
cnt_c <= cnt_c + 1;
if(cnt_c==period_c)
begin
out_c <= ~out_c;
cnt_c <= 0;
end
end
end


/////////////////////////////////////////////////////////////////////////////
// envelope generator
/////////////////////////////////////////////////////////////////////////////
reg [15:0] env_cnt;
reg [3:0] env_phase;
reg env_start;
reg env_en;
reg env_inv;


// write eshape
wire env_clr = (addr==13) & ~cs_n & ~wr_n;


// bit3 = turn reset , 0=on , 1=off
// bit2 = start , 0=up , 1=down(inv)
// bit1 = turn invert, 0=tggle , 1=fix
// bit0 = turn repeat, 0=off, 1=on


wire next_no_reset = shape_e[3];
wire start_no_inv = shape_e[2];
wire next_toggle = shape_e[1];
wire next_repeat = shape_e[0];


// envelope volume output
wire [3:0] vol_e = env_phase ^ {4{env_inv}};


//
always @(posedge clk or posedge env_clr)
begin
if(env_clr) env_start <= 1'b1;
else if(clk_en) env_start <= 1'b0;
end


always @(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
env_en <= 1'b0;
end else
if(clk_en)begin


// start trigger
if(env_start)
begin
env_cnt <= 0;
env_phase <= 0;
env_inv <= ~start_no_inv;
env_en <= 1'b1;
end


// count
if(pris==0 && env_en)
begin
// phase up
env_cnt <= env_cnt + 1;
if(env_cnt==period_e)
begin
env_cnt <= 0;
env_phase <= env_phase+1;
// turn over
if(env_phase==15)
begin
if(~next_no_reset)
begin
env_inv <= (env_inv ^ next_toggle) & next_no_reset;
env_en <= next_repeat & next_no_reset;
end
end
end
end
end
end


/////////////////////////////////////////////////////////////////////////////
// noise generator
/////////////////////////////////////////////////////////////////////////////
reg [16:0] shift_n;
reg [4:0] cnt_n;


always @(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
shift_n <= 17'b00000000000000001;
end else if((pris==0) &&(clk_en))
begin
cnt_n <= cnt_n +1;
if(cnt_n == period_n)
begin
cnt_n <= 0;
shift_n <= {shift_n[0]^shift_n[3],shift_n[16:1]};
end
end
end


wire out_n = shift_n[0];


/////////////////////////////////////////////////////////////////////////////
// volume table 3db / step
/////////////////////////////////////////////////////////////////////////////
function [7:0] vol_tbl;
input [4:0] vol;
input [3:0] vole;
input out;
begin
if(~out)
vol_tbl = 0;
else case(vol[4]?vole:vol[3:0])
15:vol_tbl = 255;
14:vol_tbl = 180;
13:vol_tbl = 127;
12:vol_tbl = 90;
11:vol_tbl = 64;
10:vol_tbl = 45;
9:vol_tbl = 32;
8:vol_tbl = 22;
7:vol_tbl = 16;
6:vol_tbl = 11;
5:vol_tbl = 8;
4:vol_tbl = 5;
3:vol_tbl = 4;
2:vol_tbl = 3;
1:vol_tbl = 2;
0:vol_tbl = 0; //1;
endcase
end
endfunction


/////////////////////////////////////////////////////////////////////////////
// output
/////////////////////////////////////////////////////////////////////////////
assign A = vol_tbl(vol_a,vol_e,(out_a | ena) & (out_n | na) );
assign B = vol_tbl(vol_b,vol_e,(out_b | enb) & (out_n | nb) );
assign C = vol_tbl(vol_c,vol_e,(out_c | enc) & (out_n | nc) );






endmodule