mirror of
				https://github.com/RfidResearchGroup/proxmark3.git
				synced 2025-10-31 16:42:34 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			416 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Verilog
		
	
	
	
	
	
			
		
		
	
	
			416 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Verilog
		
	
	
	
	
	
| 
 | |
| //this code demodulates and modulates signal as described in ISO/IEC 18092.  That includes packets used for Felica, NFC Tag 3, etc. (which do overlap)
 | |
| //simple envelope following algorithm is used (modification of fail0verflow LF one) is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave) 
 | |
| // only 212 kbps (fc/64) for now 414 is relatively straightforward... though for reader, the selection has to come from ARM
 | |
| // modulation waits for 
 | |
| //market sprocket -doesn't really mean anything ;) 
 | |
| //redefining mod_type: bits 210: bit 2 - reader drive/power on/off,  bit 1 -  speed bit, 0:212, 1 -424   bit 0: listen or modulate
 | |
| 
 | |
| 
 | |
| module hi_flite(
 | |
|     pck0, ck_1356meg, ck_1356megb,
 | |
|     pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
 | |
|     adc_d, adc_clk,
 | |
|     ssp_frame, ssp_din, ssp_dout, ssp_clk,
 | |
|     cross_hi, cross_lo,
 | |
|     dbg,
 | |
|     mod_type //  used
 | |
|     
 | |
| );
 | |
|     input pck0, ck_1356meg, ck_1356megb;
 | |
|     output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
 | |
|     input [7:0] adc_d;
 | |
|     output adc_clk;
 | |
|     input ssp_dout;
 | |
|     output ssp_frame, ssp_din, ssp_clk;
 | |
|     input cross_hi, cross_lo;
 | |
|     output dbg;
 | |
|     input [2:0] mod_type; //  used.
 | |
| assign dbg=0;
 | |
| 
 | |
| wire  power= mod_type[2];
 | |
| wire  speed= mod_type[1];
 | |
| wire  disabl= mod_type[0];
 | |
| 
 | |
| // Most off, oe4 for modulation;
 | |
| // Trying reader emulation (would presumably just require switching power on, but I am not sure) 
 | |
|  //;// 1'b0;
 | |
| assign pwr_lo  = 1'b0;
 | |
| 
 | |
| 
 | |
| 
 | |
| //512x64/fc  -wait before ts0, 32768 ticks
 | |
| //tslot: 256*64/fc
 | |
| 
 | |
| assign adc_clk = ck_1356meg;
 | |
| 
 | |
| 
 | |
| ///heuristic values for initial thresholds. seem to work OK
 | |
| `define imin 70//(13'd256)
 | |
| `define imax 180//(-13'd256)
 | |
| `define ithrmin 91//-13'd8
 | |
| `define ithrmax 160// 13'd8
 | |
| 
 | |
| `define min_bitdelay_212 8
 | |
| //minimum values and corresponding thresholds
 | |
| reg  [8:0] curmin=`imin;
 | |
| 
 | |
| reg [8:0] curminthres=`ithrmin; 
 | |
| 
 | |
| reg [8:0] curmaxthres=`ithrmax;
 | |
| reg [8:0] curmax=`imax;
 | |
| 
 | |
| 
 | |
| //signal state, 1-not modulated, 0 -modulated
 | |
| reg after_hysteresis = 1'b1;
 | |
| 
 | |
| //state machine for envelope tracking
 | |
| reg [1:0] state=1'd0;
 | |
| 
 | |
| 
 | |
| //lower edge detected, trying to  detect first bit of SYNC (b24d, 1011001001001101)
 | |
| reg try_sync=1'b0;
 | |
| 
 | |
| //detected first sync bit, phase frozen
 | |
| reg did_sync=0;
 | |
| 
 | |
| 
 | |
| `define bithalf_212 32 //half-bit length for 212 kbit
 | |
| `define bitmlen_212 63 //bit transition edge
 | |
| 
 | |
| `define bithalf_424 16 //half-bit length for 212 kbit
 | |
| `define bitmlen_424 31 //bit transition edge
 | |
| 
 | |
| wire [7:0]bithalf= speed ? `bithalf_424 : `bithalf_212;
 | |
| wire [7:0]bitmlen= speed ? `bitmlen_424 : `bitmlen_212;
 | |
| 
 | |
| 
 | |
| //ssp clock and current values
 | |
| reg ssp_clk;
 | |
| reg ssp_frame;
 | |
| reg curbit=1'b0;
 | |
| 
 | |
| reg [7:0] fccount=8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected
 | |
| 
 | |
| reg [7:0] tsinceedge=8'd0;// ticks from last edge,  desync if the valye is too large
 | |
| 
 | |
| reg zero=1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it
 | |
| 
 | |
| //ssp counter for transfer and framing
 | |
| reg [8:0] ssp_cnt=9'd0;
 | |
| 
 | |
| always @(posedge adc_clk)
 | |
|      ssp_cnt <= (ssp_cnt + 1);
 | |
| 
 | |
| //maybe change it so that ARM sends preamble as well.
 | |
| //then: ready bits sent to ARM, 8 bits sent from ARM (all ones), then preamble (all zeros, presumably) - which starts modulation    
 | |
|   
 | |
| always @(negedge adc_clk)
 | |
| begin
 | |
|      //count fc/64 - transfer bits to ARM at the rate they are received
 | |
|      if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed &&(ssp_cnt[4:0] == 5'b00000)))
 | |
|         begin
 | |
| 			ssp_clk <= 1'b1;
 | |
|            // if(mod_type[2])
 | |
|           //  begin
 | |
|          //    ssp_din<=outp[0];//after_hysteresis;
 | |
|            
 | |
|                //outp<={1'b0,outp[7:1]};             
 | |
|            //  end
 | |
|            // else
 | |
|             ssp_din <= curbit;  
 | |
|             
 | |
|             //sample ssp_dout
 | |
|                            
 | |
|         end
 | |
| 		if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000))
 | |
| 			ssp_clk <= 1'b0;
 | |
|     //create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason
 | |
|     // took me a day to figure THAT out.         
 | |
|        if(( (~speed) && (ssp_cnt[8:0] == 9'd31))||(speed && ssp_cnt[7:0] == 8'd15))
 | |
|         begin
 | |
| 			ssp_frame <= 1'b1;    
 | |
|         end
 | |
|          if(( (~speed) &&  (ssp_cnt[8:0] == 9'b1011111))||(speed &&ssp_cnt[7:0] == 8'b101111) )
 | |
|         begin
 | |
| 			ssp_frame <= 1'b0;    
 | |
|         end
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| //send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise)
 | |
| reg ssp_din;//= outp[0];    
 | |
|   
 | |
|   
 | |
| 
 | |
| //previous signal value, mostly to detect SYNC
 | |
| reg prv =1'b1;
 | |
| 
 | |
| 
 | |
| reg[7:0] mid=8'd128; //for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry. 
 | |
| 
 | |
| 
 | |
| // set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...)
 | |
| // start sending over 1s on ssp->arm when we start sending preamble
 | |
| 
 | |
| reg counting_desync=1'b0; // are we counting bits since last frame? 
 | |
| reg sending=1'b0;  // are we actively modulating? 
 | |
| reg [11:0] bit_counts=12'd0;///for timeslots... only support ts=0 for now, at 212 speed  -512 fullbits from end of frame. One hopes.   might remove those?                 
 | |
| 
 | |
| 
 | |
| //reg [2:0]old_mod;
 | |
| 
 | |
| //always @(mod_type) //when moving from modulate_mode
 | |
| //begin
 | |
| //if (mod_type[2]==1&&old_mod[2]==0)
 | |
| // bit_counts=0;
 | |
| //old_mod=mod_type; 
 | |
| //end
 | |
| //we need some way to flush bit_counts triggers on mod_type changes don't compile
 | |
| reg dlay;
 | |
| always @(negedge adc_clk) //every data ping? 
 | |
| begin
 | |
|   //envelope follow code...          
 | |
|   ////////////   
 | |
| 
 | |
|            //move the counter to the outside...
 | |
|        // if (adc_d>=curminthres||try_sync) 
 | |
|         if(fccount==bitmlen)
 | |
|   begin     
 | |
|         if((~try_sync)&&(adc_d<curminthres)&&disabl )
 | |
|         begin
 | |
|          fccount<=1;
 | |
|           end
 | |
|          else
 | |
|          begin
 | |
|           fccount<=0;
 | |
|          end 
 | |
|         // if (counting_desync)
 | |
|         //  begin
 | |
|            dlay<=ssp_dout;
 | |
|            if(bit_counts>768) // should be over ts0 now, without ARM interference... stop counting...
 | |
|               begin 
 | |
|                bit_counts<=0;
 | |
|               // counting_desync<=0;
 | |
|                end
 | |
|            else
 | |
|              if((power))
 | |
|              bit_counts<=0;
 | |
|              else
 | |
|                bit_counts<=bit_counts+1; 
 | |
|          // end 
 | |
|         end
 | |
|         else
 | |
|         begin 
 | |
|         if((~try_sync)&&(adc_d<curminthres) &&disabl)
 | |
|         begin
 | |
|          fccount<=1;
 | |
|           end
 | |
|          else
 | |
|          begin
 | |
|           fccount<=fccount+1;
 | |
|          end 
 | |
|         end
 | |
|   
 | |
|       if (adc_d>curmaxthres) //rising edge
 | |
|        begin
 | |
|         case (state)
 | |
|          0: begin
 | |
|             curmax <= adc_d>`imax? adc_d :`imax;
 | |
|             state <= 2;
 | |
|             end
 | |
|          1: begin
 | |
|             curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); //threshold: 0.1875 max + 0.8125 min
 | |
|             curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4));
 | |
|             curmax <= adc_d>155? adc_d :155; // to hopefully prevent overflow from spikes going up to 255
 | |
|             state <= 2;
 | |
|             end
 | |
|          2: begin
 | |
|             if (adc_d>curmax)
 | |
|                curmax <= adc_d;
 | |
|             end  
 | |
|          default:
 | |
|             begin
 | |
|             end        
 | |
|         endcase
 | |
|         after_hysteresis <=1'b1;
 | |
|         if(try_sync)
 | |
|           tsinceedge<=0;
 | |
|        end
 | |
|       else if (adc_d<curminthres) //falling edge
 | |
|         begin 
 | |
|           case (state)
 | |
|             0: begin
 | |
|                curmin <=adc_d<`imin? adc_d :`imin; 
 | |
|                state <=1;
 | |
|                end
 | |
|             1: begin
 | |
|                if (adc_d<curmin)
 | |
|                  curmin <= adc_d; 
 | |
|                end
 | |
|             2: begin
 | |
|                 curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4));
 | |
|                 curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4));
 | |
|                 curmin <=adc_d<`imin? adc_d :`imin;
 | |
|                 state <=1;       
 | |
|                end 
 | |
|             default:
 | |
|               begin
 | |
|               end              
 | |
|           endcase   
 | |
|               after_hysteresis <=0;
 | |
|           if (~try_sync ) //begin modulation, lower edge... 
 | |
|              begin
 | |
|              try_sync <=1;
 | |
|              //counting_desync<=1'b0;
 | |
|              fccount <= 1;
 | |
|              did_sync<=0;
 | |
|              curbit<=0;
 | |
|              mid <=8'd127;
 | |
|              tsinceedge<=0;
 | |
|              prv <=1;
 | |
|              end  
 | |
|            else
 | |
|            begin
 | |
|            tsinceedge<=0;
 | |
|            end
 | |
|          end
 | |
|         else //stable state, low or high
 | |
|          begin
 | |
|             curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4));
 | |
|             curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4));
 | |
|             state <=0;
 | |
|             
 | |
|              if (try_sync )
 | |
|               begin
 | |
|                if (tsinceedge>=(128))
 | |
|                   begin
 | |
|                   //we might need to start counting... assuming ARM wants to reply to the frame. 
 | |
|                  // counting_desync<=1'b1;
 | |
|                   bit_counts<=1;// i think? 128 is about 2 bits passed... but 1 also works
 | |
|                   try_sync<=0;
 | |
|                   did_sync<=0;//desync
 | |
|                   curmin <=`imin; //reset envelope
 | |
|                   curmax <=`imax;
 | |
|                   curminthres <=`ithrmin;
 | |
|                   curmaxthres <=`ithrmax; 
 | |
|                   prv <=1;
 | |
|                   tsinceedge <=0;
 | |
|                   after_hysteresis <=1'b1;
 | |
|                   curbit <=0;
 | |
|                   mid <=8'd128;
 | |
|                   end
 | |
|                else
 | |
|                 tsinceedge<=(tsinceedge+1);
 | |
|               end
 | |
|          end 
 | |
|         
 | |
|     
 | |
|    
 | |
|         
 | |
|         if (try_sync && tsinceedge<128)
 | |
|             begin
 | |
|             //detect bits in their middle ssp sampling is in sync, so it would sample all bits in order
 | |
|             if (fccount==bithalf)
 | |
|               begin
 | |
|                 if ((~did_sync) && ((prv==1&&(mid>128))||(prv==0&&(mid<=128))))
 | |
|                   begin 
 | |
|                         //sync the Zero, and set curbit roperly
 | |
|                         did_sync <=1'b1;
 | |
|                         zero <= ~prv;// 1-prv
 | |
|                         curbit <=1;
 | |
|                   end   
 | |
|                 else 
 | |
|                     curbit <= (mid>128) ? (~zero):zero;
 | |
|                     
 | |
|                  prv <=(mid>128) ?1:0;  
 | |
|                   
 | |
|                  if(adc_d>curmaxthres)   
 | |
|                   mid <=8'd129;
 | |
|                  else if (adc_d<curminthres) 
 | |
|                     mid <=8'd127;
 | |
|                  else 
 | |
|                   begin
 | |
|                    if (after_hysteresis)
 | |
|                    begin
 | |
|                    mid <=8'd129;
 | |
|                    end
 | |
|                    else
 | |
|                    begin
 | |
|                    mid<=8'd127;
 | |
|                    end
 | |
|                   end
 | |
|                     
 | |
|                end
 | |
|              else  
 | |
|               begin  
 | |
|                 if (fccount==bitmlen)
 | |
|                   begin
 | |
|                   // fccount <=0;
 | |
|                    prv <=(mid>128)?1:0; 
 | |
|                    mid <=128;
 | |
|                   end
 | |
|                 else
 | |
|                  begin
 | |
|                 // minimum-maximum calc
 | |
|                   if(adc_d>curmaxthres)   
 | |
|                      mid <=mid+1;
 | |
|                    else if (adc_d<curminthres) 
 | |
|                     mid <=mid-1;
 | |
|                    else 
 | |
|                     begin
 | |
|                      if (after_hysteresis)
 | |
|                        begin
 | |
|                        mid <=mid+1;
 | |
|                        end
 | |
|                        else
 | |
|                        begin
 | |
|                        mid<=mid-1;
 | |
|                        end
 | |
|                     end 
 | |
|                  end
 | |
|               end  
 | |
|             end 
 | |
|            else
 | |
|            begin
 | |
|             end       
 | |
|        sending <=0;     
 | |
| end
 | |
| //put modulation here to maintain the correct clock. Seems that some readers are sensitive to that
 | |
| reg pwr_hi;
 | |
| reg pwr_oe1;
 | |
| reg pwr_oe2;
 | |
| reg pwr_oe3;
 | |
| reg pwr_oe4;
 | |
| 
 | |
| wire mod=((fccount>=bithalf)^dlay)&(~disabl);
 | |
| 
 | |
| always @(ck_1356megb or ssp_dout or power or disabl or mod)
 | |
|         begin
 | |
| if (power)
 | |
|            begin
 | |
|         pwr_hi <= ck_1356megb;
 | |
|         pwr_oe1 <= 1'b0;//mod;
 | |
|         pwr_oe2 <= 1'b0;//mod;
 | |
|         pwr_oe3 <= 1'b0;//mod;
 | |
|         pwr_oe4 <= mod;//1'b0;
 | |
|            end
 | |
| else
 | |
|           begin          
 | |
|        pwr_hi <= 1'b0;
 | |
|         pwr_oe1 <= 1'b0;
 | |
|         pwr_oe2 <= 1'b0;
 | |
|         pwr_oe3 <= 1'b0;
 | |
|         pwr_oe4 <= mod;
 | |
|             end
 | |
|             end
 | |
| //assign pwr_oe4 = 1'b0;// mod_sig_coil  & (modulate_mode)&sending & (~mod_type[2]);
 | |
| //try shallow mod for reader?
 | |
| //assign pwr_hi= (mod_type[2]) & ck_1356megb;
 | |
| //assign pwr_oe1= 1'b0; //mod_sig_coil  & (modulate_mode)&sending & (mod_type[2]);
 | |
| //assign pwr_oe2 = 1'b0;// mod_sig_coil  & (modulate_mode)&sending & (mod_type[2]);
 | |
| //assign pwr_oe3 = 1'b0; //mod_sig_coil  & (modulate_mode)&sending & (mod_type[2]);
 | |
| 
 | |
| endmodule
 |