// Description: // ************ // MFM ENcoder for RL02 disk simmulator with 16 bit parallel input // and serial output. In this case, the serial transfer clock runs // at 4.1 Mhz. The clock input is 16.4 MHz, obtained from a PLL to // get the double frequency of 8.2 MHz, necessary for MFM phase // shifting. The 16bit transfer rate runs at 256.250 KHz. // ( A special feature is implemented through the input // "select_pulse_width".In this case, the MFM pulse-width is // selectable, either at ~60us or at ~120us ) .. no longer needed! // // TIME-shifting: // ************** // |<------ shift <-------- shift <----------- shift <-----------| // | | ********* LSB first ********* | // |<-16Bit SR history[15:0]->|<-16Bit shift/load,shifter[15:0]->| // |15 -> |9|8|7|6| <- 00|00 -----------------------------15| // | | | | // | | | +---> naechst(next) history[6] // | | +-----> jetzt (current) history[7] -> serial_OUT // | +-------> alt (old) history[8] // +---------> uralt (very old) history[9] // // PHASE shifting: // *************** // 8.2 MHz: ..._|----____----____|----____----____..... // 4.1 MHz: ..._|--------________|--------________..... // phase_0 ..._|________________|________________..... // phase_1 ..._|----____________|----____________..... // phase_2 ..._|____----________|____----________..... // phase_3 ..._|________----____|________----____..... // phase_4 ..._|____________----|____________----..... // // by: Reinhard Heuberger , www.PDP11GY.com, JUL, 2011 // // Improvement implemented to run full synchronously, // // // V 3.2 : Note: shift-direction is LSB first ! // V 3.3 : 16Bit allignment implemented. // V 3.4 : Code improved (case statement) to get a generally // purpose design with 8 Bit allignment. This code // also can be used for ENcoding other protocols, // like FM, GCR and Manchester-Coding. // module my_MFM_ENcoder_V3_4( data_end, // data_end inside one sector sector, // Start if sector High. clk_16_4, // Input Clock 16.4 MHz clk_50, // System Clock 50.0 MHz data_16_in, // Data, 16 Bit parallel in //select_pulse_width, // MFM pulse width mode // CLK_8_2, // Out-Clock 8.2MHz CLK_4_1, // Out-Clock 4.1MHZ CLK_16bit, // Out-clock, 16Bit serial_OUT, // Data, Serial out load_L, // SR load pulse MFM); // MFM out // input data_end, sector, clk_16_4, clk_50; //input select_pulse_width; input [15:0] data_16_in; output CLK_8_2, CLK_4_1, CLK_16bit, serial_OUT, load_L, MFM; // reg [31:0] divider; // counter,= clock generator. reg [15:0] shifter; // 16Bit parallel in SR reg [15:0] history; // jetzt, alt, uralt SR. reg [3:0] load_SR; // load-puls generator SR reg [2:0] rclksync_16_4; // like 2 D-FF register, reg clk_4_1_p; // Synchronized 4.1MHz Clock reg MFM; // MFM out //wire [3:0] check; //wire [2:0] check; //wire uebernaechst; // = after next (not used in this version) //wire naechst; // = next (not used in this version) //wire jetzt; // = current (not used in this version) //wire alt; // = old (not used in this version) //wire uralt; // = very old (not used in this version) wire syncposedge_clk_16_4; reg ph0, ph1, ph2, ph3; //reg ph4; wire phase_0, phase_1, phase_2, phase_3, shifter_out; //wire phase_4; // initial begin divider = 0; shifter = 0; history = 0; end // /* //=============== Synchronize 16.4Mhz clock to FPGA clock ==================== //============================================================================ always @ (posedge clk_50) begin if ( !sector & !data_end ) rclksync_16_4 <=0; else if ( sector & data_end ) rclksync_16_4[2:0] <= { rclksync_16_4[1:0] , clk_16_4 }; end assign syncposedge_clk_16_4 = !rclksync_16_4[2] & rclksync_16_4[1]; */ // // //========================== Counter/Divider ================================= //============================================================================ // Note: Counting up is done at negative edges. // Counting down is done at positive edges. always @ (posedge clk_50) begin if ( !sector & !data_end ) divider <= 0; else if ( sector & data_end ) divider <= (data_end & syncposedge_clk_16_4) ? divider - 1 : divider; end assign CLK_8_2 = divider[0]; // Output: 8.2Mhz assign CLK_4_1 = divider[1]; // Output: 4.1MHz assign CLK_16bit = divider[5]; // Output 16Bit Clock // // //============== MFM phase and pulse-width generator ========================= //============================================================================ always @ (posedge clk_50) begin /* ph0 <= ( select_pulse_width ) ? 0 : 0; ph1 <= ( select_pulse_width ) ? (CLK_4_1 && CLK_8_2) : (CLK_4_1); ph2 <= ( select_pulse_width ) ? (CLK_4_1 && !CLK_8_2) : (CLK_4_1 ^ CLK_8_2); ph3 <= ( select_pulse_width ) ? (!CLK_4_1 && CLK_8_2) : (!CLK_4_1); //ph4 <= ( select_pulse_width ) ? (!CLK_4_1 && !CLK_8_2) : (!CLK_4_1 ^ !CLK_8_2); */ ph0 <= 0; ph1 <= ( CLK_4_1 && CLK_8_2); ph2 <= ( CLK_4_1 && !CLK_8_2); ph3 <= (!CLK_4_1 && CLK_8_2); end assign phase_0 = ph0; assign phase_1 = ph1; assign phase_2 = ph2; assign phase_3 = ph3; //assign phase_4 = ph4; // // //===================== Generate a 20ns load pulse =========================== //============================================================================ always @(posedge clk_50) begin load_SR = {load_SR[2:0], CLK_16bit}; // shift end assign load_L = ~((load_SR[2] ^ CLK_16bit) & CLK_16bit); // // //========================= Mofify 4.1MHz clock ============================= //============================================================================ always @ (posedge clk_50) begin clk_4_1_p <= CLK_4_1; end // // //=============== Shiftregister with synchronous parallel load =============== //============================================================================ //always @(posedge clk_4_1_p or negedge load_L ) // Asynchron //always @(posedge clk_4_1_p ) // "Synchron" always @ (posedge clk_50) // Full Synchron ! begin if(!sector & !data_end ) shifter = 0; else if ( !clk_4_1_p & CLK_4_1 ) // Full Synchron ! begin if (!load_L ) // IF load begin shifter <= data_16_in; // than (re)load end else if (load_L) begin shifter = shifter >> 1; // else shift end end end assign shifter_out = shifter[0]; // // //========================= History shiftregister =========================== //============================================================================ //always @(posedge clk_4_1_p ) always @ (posedge clk_50) begin if ( !clk_4_1_p & CLK_4_1 ) begin // history = {history[15:0], shifter_out}; // shift // end end assign serial_OUT = history[7]; //assign check[3:0] = history[9:6]; //assign check[2:0] = history[9:7]; //assign uebernaechst = history[5]; //assign naechst = history[6]; //assign jetzt = history[7]; //assign alt = history[8]; //assign uralt = history[9]; // // //============================ MFM - ENcoder ================================= //============================================================================ always @(posedge clk_50) begin if (sector & data_end) begin case (history[9:7]) 3'b000: MFM <= phase_1; // 00->0 3'b001: MFM <= phase_3; // 00->1 3'b010: MFM <= phase_0; // 01->0 3'b011: MFM <= phase_3; // 01->1 3'b100: MFM <= phase_1; // 10->0 3'b101: MFM <= phase_2; // 10->1 ! 3'b110: MFM <= phase_0; // 11->0 3'b111: MFM <= phase_3; // 11->1 /* case (check[3:0]) // MFM spezifisch: Von 1 -> einer(!) 0 mit folgender 1 : // 1 auf 0 wird immer Phase_0, aber um die darauf folgende // richtig zu encoden, muss eine phase2 gesendet werden. \|/ 4'b0000: MFM <= phase_1; // 00->0 followed 0 4'b0001: MFM <= phase_1; // 00->0 followed 1 4'b0010: MFM <= phase_3; // 00->1 followed 0 4'b0011: MFM <= phase_3; // 00->1 followed 1 4'b0100: MFM <= phase_0; // 01->0 followed 0 4'b0101: MFM <= phase_0; // 01->0 followed 1 4'b0110: MFM <= phase_3; // 01->1 followed 0 4'b0111: MFM <= phase_3; // 01->1 followed 1 4'b1000: MFM <= phase_1; // 10->0 followed 0 4'b1001: MFM <= phase_1; // 11->0 followed 1 4'b1010: MFM <= phase_2; // 10->1 followed 0-!! 4'b1011: MFM <= phase_2; // 10->1 followed 1 4'b1100: MFM <= phase_0; // 11->0 followed 0 4'b1101: MFM <= phase_0; // 11->0 followed 1 4'b1110: MFM <= phase_3; // 11->1 followed 1 4'b1111: MFM <= phase_3; // 11->1 followed 1 */ // default: MFM <= 0; endcase end else begin MFM <= 0; end end // endmodule