Цитата Сообщение от Tronix Посмотреть сообщение
все ссылки битые.

Скрытый текст

Код:
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
[свернуть]