ai_controller.v 13 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
/************************************************************************\
|                                                                        |
|               Copyright (C) 1994, Silicon Graphics, Inc.               |
|                                                                        |
|  These coded instructions, statements, and computer programs  contain  |
|  unpublished  proprietary  information of Silicon Graphics, Inc., and  |
|  are protected by Federal copyright  law.  They  may not be disclosed  |
|  to  third  parties  or copied or duplicated in any form, in whole or  |
|  in part, without the prior written consent of Silicon Graphics, Inc.  |
|                                                                        |
\************************************************************************/

// initial ai_controller.v 1.2 Tue Sep 27 22:38:24 PDT 1994 rhn
// $Id: ai_controller.v,v 1.1.1.1 2002/05/17 06:14:57 blythe Exp $

// 10/10/94, debug stuff removed, rhn
// 10/27/94, moved full flag to lsb of status reg, rhn
// 12/01/94, added synchronizers
// 12/07/94, flipped abus_word left-right meaning
// 12/10/94, dma_address structure changes for simulation reset, kmh
// 12/11/94, used reset_l to get to resetable flops, kmh
// 12/12/94, length state machine rewrite

module ai_controller(
	clk,
	reset_l,
	dma_grant,
	dma_start,
	reg_write_data,
	reg_address,
	reg_write_enable,
	abus_word,
	test_data,
	dbus_data,
	dma_request,		// outputs
	dma_address,
	reg_read_data,
	bit_rate_reg,
	dac_rate_reg,
	current_sample,
	interrupt_flag
	);

  `include "ai.vh"

  input clk;                                   // system clock
  input reset_l;                               // system reset

  input dma_grant;                             // grant the DMA operation
  input dma_start;                             // start the DMA operation
  input [CBUS_DATA_SIZE-1:0] reg_write_data;   // register write data from cbus
  input [AI_REG_ADDRESS_SIZE-1:0] reg_address; // register read/write address
  input reg_write_enable;                      // register write enable
  input	abus_word;			       // input sample clock
  input [DBUS_DATA_SIZE-1:0] dbus_data;        // DMA bus

  input [15:0] test_data;
  
  output dma_request;                          // request a DMA read cycle
  output [DRAM_ADDRESS_SIZE-1:0] dma_address;  // DMA slave address
  output [CBUS_DATA_SIZE-1:0] reg_read_data;   // register read data to cbus

  output [BIT_RATE_SIZE-1:0]	bit_rate_reg;	// dac clk rate
  output [DAC_RATE_SIZE-1:0]	dac_rate_reg;	// dac sample rate
  output [SAMPLE_WORD_SIZE-1:0]	current_sample;	// current 2*16 bit sample
  output interrupt_flag;			// 
  
  // input/output registers
  reg dma_request;

  //  internal fifo control set-reset flags
  reg length2_loaded_flag;		// both length registers are in use
  reg length_zero;
  reg dfifo2_loaded_flag;		// both dma data regs are in use
  reg data_available_flag;		// dma data is available
  reg word_select;			// which half of dma data to use
  reg interrupt_flag;			// 

  // internal registers
  reg dma_busy;
  reg dma_enable;
  reg [CBUS_DATA_SIZE-1:0] reg_read_data;
  reg [CBUS_DATA_SIZE-1:0] status_data;
  reg [DRAM_ADDRESS_SIZE-1:0] next_dma_address;
  reg [DRAM_ADDRESS_SIZE-1:0] dma_address;
  reg [LENGTH_COUNT_SIZE-1:0] length_reg;
  reg [LENGTH_COUNT_SIZE-1:0] next_dma_length;
  reg [DBUS_DATA_SIZE-1:0] audio_data;
  reg [DBUS_DATA_SIZE-1:0] next_data;
  reg	[3:0]	bit_rate_reg;
  reg	[DAC_RATE_SIZE-1:0] dac_rate_reg;
  reg	[31:0]	current_sample;
  wire abus_word1;		
  wire abus_word2;		// pipeline reg for syncronization
  wire abus_word3;		// pipeline reg for edge detection
  reg addr_carry_flag;		// carry flag for split dma_address
  reg state;

  // psuedo regs
  reg [DRAM_ADDRESS_SIZE-1:13] adrs_upr ;
  reg [12:3] adrs_lwr;
  reg adrs_lwr_cout;
  reg adrs_inc_lwr;
  reg adrs_load;

  // state machine defines
  parameter
     STATE_IDLE           = 1'd0,
     STATE_READ           = 1'd1;

  // instanciated hardened synchronizer flops
  dfntnb ai_sync_3 (.cp(clk), .d(abus_word2), .q(abus_word3));
  dfntnb ai_sync_2 (.cp(clk), .d(abus_word1), .q(abus_word2));
  dfntnb ai_sync_1 (.cp(clk), .d(abus_word),   .q(abus_word1));

  // old sync flops
  // always @(posedge clk) begin
     // abus_word3 <= abus_word2;
     // abus_word2 <= abus_word1;
     // abus_word1 <= abus_word;
  // end

  // length == 0 comparitor
  always @(length_reg) begin
    length_zero = (length_reg == 0);
  end

  //synopsys translate_off
  // reg monitor;
  // initial monitor = $test$plusargs("ai_mon");
  //synopsys translate_on

  // test display
  // always @( negedge clk ) begin
    // $display("%b %h %h - %b %h %b %b %b - %b %h %b %h - %b %b %b %h ",
      // length2_loaded_flag, next_dma_length, length_reg,
      // dma_enable, state,
      // dma_request, dma_grant, dma_start,
      // dfifo2_loaded_flag, next_data,
      // data_available_flag, audio_data,
      // abus_word2, abus_word3, word_select, current_sample
      // );
  // end
  // always @( negedge clk ) begin
    //$display("%b %h %h - %b %b",
      //length2_loaded_flag, next_dma_length, length_reg,
      //state, dma_start,
      //);
  //end

  // length register fifo state machine rewrite

  reg [DRAM_ADDRESS_SIZE-1:0] dma_address_temp;
  reg [LENGTH_COUNT_SIZE-1:0] length_reg_temp;
  reg length2_loaded_flag_temp;
  reg interrupt_flag_temp;
  reg addr_carry_flag_temp;

  // combinatoric logic
  always @(	dma_address or
		next_dma_address or 
		length_reg or
		next_dma_length or
		length_zero or 
		length2_loaded_flag or
		addr_carry_flag or
		interrupt_flag or
		reg_write_enable or
		reg_address or
		state or
		dma_start or
		bit_rate_reg
		) begin

	// pre-init to prevent latches from being generated
	length_reg_temp			= length_reg;
	length2_loaded_flag_temp	= length2_loaded_flag;
	interrupt_flag_temp		= interrupt_flag;
	addr_carry_flag_temp		= addr_carry_flag;
	dma_address_temp[DRAM_ADDRESS_SIZE-1:3] 
			= dma_address[DRAM_ADDRESS_SIZE-1:3];
	dma_address_temp[2:0]		= 3'b0;

	if ( length2_loaded_flag == 0 ) begin
	  if ( reg_write_enable == 1 && reg_address == AI_LENGTH_REG ) begin
	      length2_loaded_flag_temp	= 1;
	  end
	end
	else begin
	  if ( length_zero ) begin
              length2_loaded_flag_temp	= 0;
	  end
	end

        if ( reg_write_enable && ( reg_address == AI_STATUS_REG ) &&
	    (interrupt_flag == 1) ) begin
          interrupt_flag_temp	= 0;
	  // $display("interrupt off %d", $time);
        end

	if ( length_zero ) begin
          if ( length2_loaded_flag == 1 ) begin
            length_reg_temp		= next_dma_length;
	    dma_address_temp[DRAM_ADDRESS_SIZE-1:3]
			 = next_dma_address[DRAM_ADDRESS_SIZE-1:3];
            // length2_loaded_flag_temp	= 0; // set in another block
 
	    if (interrupt_flag == 0) begin
              interrupt_flag_temp	= 1;
	      // $display("interrupt on %d", $time);
	    end
          end
	end
	else begin					// length_reg != 0
          if ( state == STATE_READ && dma_start == 1 ) begin
	    // got DMA data 
	    // decrement length & increment address
	    length_reg_temp	= length_reg - 1;
	    { addr_carry_flag_temp, dma_address_temp[12:3] }
	   			= { 1'b0, dma_address[12:3] } + 1;
	  end
	  else begin
	    if ( addr_carry_flag == 1 ) begin
	      dma_address_temp[DRAM_ADDRESS_SIZE-1:13]
			= dma_address[DRAM_ADDRESS_SIZE-1:13] + 1;
	      addr_carry_flag_temp	= 0;
	    end
	    // flush length functionality
	    if ( bit_rate_reg == 0 ) begin
	      length_reg_temp		= 0;
	    end
	  end
	end						// length_reg != 0
  end // combinatorial logic

  // length state machine registers
  always @( posedge clk or negedge reset_l ) begin
    if ( reset_l == 0 ) begin
      length_reg		<= 0;
      length2_loaded_flag	<= 0;
      interrupt_flag		<= 0;
      addr_carry_flag		<= 0;
      // dma_address		<= 24'bx;
      dma_address[DRAM_ADDRESS_SIZE-1:14] <= 13'bx;
      dma_address[13]		<= 0;		// force reset (why?)
      dma_address[12:4]		<= 9'bx;
      dma_address[3]		<= 0;		// force reset (why?)
      dma_address[2:0]		<= 3'bx;
    end
    else begin
      length_reg		<= length_reg_temp;
      length2_loaded_flag	<= length2_loaded_flag_temp;
      interrupt_flag		<= interrupt_flag_temp;
      addr_carry_flag		<= addr_carry_flag_temp;
      dma_address 		<= dma_address_temp;
    end
  end

  // sound data fifo state machine

  always @( posedge clk or negedge reset_l ) begin
     if ( reset_l == 0 ) begin
	word_select		<= 0;
	data_available_flag	<= 0;
	dfifo2_loaded_flag	<= 0;
	current_sample		<= 0;	// reset to avoid pop
	// dont care's during reset
	audio_data		<= 'bx;
	next_data		<= 'bx;
     end
     else begin
       if ( data_available_flag == 0 ) begin
	 if ( dfifo2_loaded_flag == 1 ) begin
	   				// load data from next to current
	   data_available_flag	<= 1;
	   audio_data		<= next_data;
	   word_select		<= 1;
	   dfifo2_loaded_flag	<= 0;
	 end
       end
       else begin 	// ( data_available_flag == 1 )
	 if ( abus_word3 == 0 && abus_word2 == 1 ) begin  // rising edge
	   if ( word_select == 1 ) begin
             current_sample <= audio_data[63:32];	// high word 1st
	     word_select		<= 0;
	   end
	   else begin
             current_sample <= audio_data[31:0];	// low word 2nd
	     data_available_flag	<= 0;
	   end
	   // $display("ai_current sample %8h", audio_data);
	 end
       end
       if ( dfifo2_loaded_flag == 0 ) begin
         if ( state == STATE_READ && dma_start ) begin	// got DMA data 
	   				// load next data line 
	   dfifo2_loaded_flag	<= 1;
           next_data		<= dbus_data;
	   // $display("ai_next sample %8h", dbus_data);
	 end
       end

     end
  end

  // dma_request state machine

  always @( posedge clk or negedge reset_l ) begin
    if ( reset_l == 0 ) begin
       state		<= STATE_IDLE;
       dma_busy		<= LOW;
       dma_request	<= LOW;
    end
    else begin
       case (state)
           STATE_IDLE : begin
	       if ( dma_request == LOW && dma_busy == LOW ) begin
		 if ( dma_enable == 1 &&
		      !length_zero && dfifo2_loaded_flag == 0 ) begin
		   dma_busy	<= HIGH;
		   dma_request	<= HIGH;
		 end
	       end
               if ( dma_request == HIGH && dma_grant ) begin		
	         dma_request	<= LOW; 	// DMA operation has begun
                 state		<= STATE_READ;
               end
               else begin
                 state		<= STATE_IDLE;
               end
             end

           STATE_READ : begin
	       if ( dma_start ) begin
	         if ( dma_busy == HIGH ) begin
	           dma_busy	<= LOW; 	// got DMA data 
		 end
                 state		<= STATE_IDLE;
	       end
               else begin
                 state		<= STATE_READ;
               end
             end
	   // state decode is complete
        endcase
     end
  end

  // register write logic

  always @( posedge clk or negedge reset_l ) begin
     if (reset_l == 0) begin
	bit_rate_reg	<= 0;		// reset for testability
        dma_enable	<= 0;
	dac_rate_reg	<= 0;           // reset for testability
	next_dma_address <= 24'bx;
	next_dma_length  <= 18'bx;
     end
     else begin
        if ( reg_write_enable ) begin
	   case (reg_address) // synopsys full_case parallel_case
              AI_DRAM_ADDRESS_REG : begin
                  next_dma_address	<= { reg_write_data[31:3], 3'b0 };
                end

              AI_LENGTH_REG : begin
                  next_dma_length <= reg_write_data[LENGTH_COUNT_SIZE-1:3];

                  // if (length2_loaded_flag) begin
                    // $display("Panic!  AI DMA request overflow.");
                  // end
                end

              AI_DACRATE_REG : begin
		  dac_rate_reg <= reg_write_data[DAC_RATE_SIZE-1:0];
	          // $display("ai_dac_rate %8h", reg_write_data);
                end

              AI_BITRATE_REG : begin
		  bit_rate_reg <= reg_write_data[3:0];
	          // $display("ai_bit_rate %8h", reg_write_data);
                end

	      AI_CONTROL_REG : begin
		  dma_enable   <= reg_write_data[0];
                end

              default : begin
                 // $display("Panic!  Illegal AI register write - <%h>.",
                   // reg_address);
                 // $finish;
                end
           endcase
         end  // reg_write_enable
     end  // not reset
  end  // always

  //  status register
  always @( length2_loaded_flag or length_zero or
	    dma_busy or dma_request or dma_enable or
	    dfifo2_loaded_flag or data_available_flag or word_select or
	    abus_word2 or test_data ) begin

    status_data = { length2_loaded_flag, !length_zero, 2'b0,
		    dma_busy, dma_request, dma_enable, 1'b1,
		dfifo2_loaded_flag, data_available_flag, word_select, 1'b1,
		    abus_word2, 2'b0, test_data[0],
		    test_data[15:1] ,length2_loaded_flag};
    // $display("ai_status reg read %h", status_data);
  end

  // register read mux
  always @( reg_address or length_reg or status_data ) begin

     case (reg_address)
	// AI_DRAM_ADDRESS_REG : reg_read_data = dma_address;
	AI_LENGTH_REG : reg_read_data = { 11'b0, length_reg, 3'b0 };
	AI_STATUS_REG : reg_read_data = status_data;
	default :       reg_read_data = { 11'b0, length_reg, 3'b0 };
					// for complete decode
    endcase
  end

endmodule
// eof