nmea_decoder393.v 16.4 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: nmea_decoder393
 * Date:2015-07-06  
4
 * Author: Andrey Filippov     
5 6
 * Description: Decode some of the NMEA sentences (to compress them)
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19
 * nmea_decoder393.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  nmea_decoder393.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
20 21 22 23 24 25
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
26
 * files and/or simulating the code, the copyright holders of this Program give
27 28
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
Andrey Filippov's avatar
Andrey Filippov committed
29
 * charge, and there is no dependence on any encrypted modules for simulating of
30 31 32
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
33 34 35 36
 *******************************************************************************/
`timescale 1ns/1ps

module  nmea_decoder393(
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
    input                         mclk,    // system clock, posedge
    input                         xclk,    // half frequency (80 MHz nominal)
    input                         we,     // registers write enable (@negedge mclk)
    input                   [4:0] wa,     // registers write address
    input                   [7:0] wd,     // write data
    input                         start,  // start of the serail message
    input                         rs232_wait_pause,// may be used as reset for decoder
    input                         start_char,           // serial character start (single pulse)
    output reg                    nmea_sent_start,  // serial character start (single pulse)
    input                         ser_di, // serial data in (LSB first)
    input                         ser_stb,// serial data strobe, single-cycle, first cycle after ser_di valid
    output                        rdy,    // encoded nmea data ready
    input                         rd_stb, // encoded nmea data read strobe (increment address)
    output                 [15:0] rdata,   // encoded data (16 bits)
    input                         ser_rst,
    output                 [23:0] debug);
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
    reg    [ 9:0] bitnum;
    reg           gp_exp_bit;                   
    reg           valid;              // so far it is a valid sentence
    reg     [3:0] sentence1hot;       // one-hot sentence, matching first 6 bytes ($GPxxx)
    reg           restart;            // reset byte number if the first byte was not "$"
    reg           start_d;
    reg     [3:0] stb;                // ser_stb delayed
    reg           msb,bits37,bit3;
    reg           vfy_dollar;
    reg           vfy_gp;
    reg           vfy_sel_sent;
    reg           vfy_first_comma;    // first comma after $GPxxx
    reg           proc_fields;
    reg           last_vfy_gp;        // delayed by 1 cycle from bit counters
    reg           last_vfy_sent;      // delayed by 1 cycle from bit counters
    reg           lsbs5;              // 5 LSBs during reading 3 last letters in $GPxxx
    reg     [3:0] gpxxx_addr;
    wire    [3:1] sentence1hot_pri;   // sentence1hot made really one-hot
    reg     [1:0] sentence;           // decoded sentence number (0..3)
    reg     [4:0] format_length;      // number of fields in the sentence
    reg     [4:0] format_length_plus_7;
    reg     [4:0] format_field;       // current number of the field in the sentence
    wire          start_format;
    reg           read_format_length; //, read_format_length_d;
    reg           read_format_byte;
    reg           shift_format_byte;
    reg           format_over;
    reg           sentence_over;
    reg     [7:0] format_byte;
    reg     [7:1] last_byte;
    wire          wcomma;             // comma
    wire          weof;               //asterisk, or cr/lf (<0x10)
    wire          wsep;               //any separator 
    reg     [3:0] nibble;
    reg     [3:0] nibble_pre;
    wire    [7:0] wbyte;
    reg           nibble_stb;
    reg           first_byte_in_field;
    reg     [1:0] extra_nibble;       // empty byte field - send two 4'hf nibbles
    reg     [6:0] nibble_count;
    reg     [4:0] raddr;
    wire    [3:0] gpxxx_w_one;
    wire    [7:0] format_data;
    wire          w_sentence_over;
    reg     [4:0] last_word_written;  // number of the last word (4 nibbles) written - used ro deassert rdy (garbage after)
    reg           rdy_r=1'b0;
    reg           save_sent_number;
    reg    [ 7:0] debug0;
    reg    [15:0] debug1;
    reg    [15:0] debug1_or;
104

105 106 107 108 109 110 111 112
    assign debug[23:0] =  {1'b0,
                           proc_fields,
                           vfy_first_comma,
                           vfy_sel_sent,
                           vfy_gp,
                           vfy_dollar,
                           bitnum[9:0],
                           debug0[7:0]};
113

114 115 116 117
    assign sentence1hot_pri[3:1] = {sentence1hot[3]& ~|sentence1hot[2:0],
                                    sentence1hot[2]& ~|sentence1hot[1:0],
                                    sentence1hot[1]&  ~sentence1hot[0]};
    assign start_format=           (vfy_first_comma && (sentence1hot[3:0]!=4'h0) && (stb[3] && msb));
118
  
119 120 121 122 123 124 125
    assign wbyte[7:0] =            {ser_di,last_byte[7:1]}; // valid up to stb[3];
    assign wcomma =                proc_fields && msb && (wbyte[7:0]==8'h2c);
    assign weof =                  proc_fields && msb && ((wbyte[7:0]==8'h2a) || (wbyte[7:4]==4'h0)); // 0x2a or 0x0? (<0x10)
    assign wsep =                  wcomma || weof;
    assign w_sentence_over =       wsep && (format_field[4:0]==format_length_plus_7[4:0]);
    assign rdy =                   rdy_r;
    
126
//format_length_plus_7
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
    always @ (posedge xclk) begin
        if (ser_rst) debug0 [7:0] <= 8'b0;
        else debug0 [7:0] <=debug0 [7:0] | {rdy_r,
                                          proc_fields,
                                          shift_format_byte,
                                          start_format,
                                          vfy_first_comma,
                                          vfy_sel_sent,
                                          vfy_gp,
                                          vfy_dollar};
    
        if (ser_rst) debug1 [15:0] <= 16'b0;
        else if (stb[1] && vfy_sel_sent && lsbs5) debug1 [15:0] <= debug1 [15:0] | debug1_or [15:0];
    
        case (gpxxx_addr[3:0])
            4'h0:  debug1_or[15:0] <= 16'h0001;
            4'h1:  debug1_or[15:0] <= 16'h0002;
            4'h2:  debug1_or[15:0] <= 16'h0004;
            4'h3:  debug1_or[15:0] <= 16'h0008;
            4'h4:  debug1_or[15:0] <= 16'h0010;
            4'h5:  debug1_or[15:0] <= 16'h0020;
            4'h6:  debug1_or[15:0] <= 16'h0040;
            4'h7:  debug1_or[15:0] <= 16'h0080;
            4'h8:  debug1_or[15:0] <= 16'h0100;
            4'h9:  debug1_or[15:0] <= 16'h0200;
            4'ha:  debug1_or[15:0] <= 16'h0400;
            4'hb:  debug1_or[15:0] <= 16'h0800;
            4'hc:  debug1_or[15:0] <= 16'h1000;
            4'hd:  debug1_or[15:0] <= 16'h2000;
            4'he:  debug1_or[15:0] <= 16'h4000;
            4'hf:  debug1_or[15:0] <= 16'h8000;
        endcase
                                          
        stb[3:0] <= {stb[2:0], ser_stb};
        start_d <= start;
        restart <= start || sentence_over || stb[2] && msb && ((!valid && (vfy_dollar || last_vfy_gp || vfy_first_comma)) || // may abort earlier (use vfy_gp)
                                              ((sentence1hot==4'h0) &&  last_vfy_sent)); // may abort earlier (use vfy_sel_sent)
     
        if      (start_d)  bitnum[2:0] <= 3'h0;
        else if (stb[3]) bitnum[2:0] <= bitnum[2:0] + 1;
    
        if      (start_d)  msb <= 1'b0;
        else if (stb[3])   msb <= (bitnum[2:0] ==3'h6);
    
        if      (start_d)  bit3  <= 1'b0;
        else if (stb[3])   bit3 <= (bitnum[2:0] ==3'h2);
    
        if      (start_d)  bits37 <= 1'b0;
        else if (stb[3])   bits37 <= (bitnum[1:0] ==2'h2);
    
        if      (start_d)  lsbs5 <= 1'b1;
        else if (stb[3])   lsbs5 <= !bitnum[2] || (bitnum[2:0] ==3'h7);
        
        if      (restart)       bitnum[9:3] <= 'h0;
        else if (stb[3] && msb) bitnum[9:3] <=  bitnum[9:3] + 1;
        
        if      (restart || rs232_wait_pause)  vfy_dollar <= 1'b1;  // byte 0
        else if (stb[3] && msb)                vfy_dollar <= 1'b0;
    
        last_vfy_gp <= vfy_gp && !bitnum[3];
187

188 189 190 191
        if      (restart)       vfy_gp <= 1'b0;
        else if (stb[3] && msb) vfy_gp <= (valid && vfy_dollar) || (vfy_gp && !last_vfy_gp); // bytes 1-2
    
        last_vfy_sent <= vfy_sel_sent && (bitnum[3] && bitnum[5]);
192

193 194 195 196 197 198 199 200 201
        if      (restart)       vfy_sel_sent <= 1'b0;
        else if (stb[3] && msb) vfy_sel_sent <= (valid && last_vfy_gp) || (vfy_sel_sent && !last_vfy_sent); // bytes 3,4,5
    
        if      (restart)       vfy_first_comma <= 1'b0;
        else if (stb[3] && msb) vfy_first_comma <= last_vfy_sent;
        
        if (restart)                                                      valid <= 1'b1; // ready @ stb[2]
        else if (stb[1] && (ser_di!=gp_exp_bit) &&
                           (vfy_dollar || vfy_gp || vfy_first_comma || (vfy_sel_sent && !lsbs5))) valid <= 1'b0;
202
    
203 204 205 206 207 208
     
        if       (!vfy_sel_sent) gpxxx_addr[3:0] <= 4'h0;
        else if (lsbs5 &&stb[3]) gpxxx_addr[3:0] <= gpxxx_addr[3:0] + 1;
        
        if (vfy_gp)                                sentence1hot[3:0] <= 4'hf;
        else if (stb[1] && vfy_sel_sent && lsbs5)  sentence1hot[3:0] <= sentence1hot & (ser_di?(gpxxx_w_one[3:0]): (~gpxxx_w_one[3:0]));
209
    
210 211 212 213 214 215 216 217
        if (last_vfy_sent && stb[3] && msb) sentence[1:0] <= {sentence1hot_pri[3] | sentence1hot_pri[2], sentence1hot_pri[3] | sentence1hot_pri[1]};
        
        if (restart || sentence_over) proc_fields <=1'b0;
        else if (start_format)        proc_fields <=1'b1;
        
        if (!proc_fields)            format_field[4:0] <= 5'h0;
        else if (read_format_length) format_field[4:0] <= 5'h8;
        else if (format_over)        format_field[4:0] <= format_field[4:0] + 1;
218

219
        format_length_plus_7[4:0] <= format_length[4:0]+7;
220

221 222 223 224 225 226 227 228
        if      (start_format)  first_byte_in_field <=1'b1;
        else if (stb[3] && msb) first_byte_in_field <=  format_over;
        
        read_format_length <= start_format;
        
        if (read_format_length) format_length[4:0] <= format_data[4:0];
        
        read_format_byte <= read_format_length || (format_over && format_field[2:0]==3'h7); // @stb[4]
229

230
        shift_format_byte <= format_over; // @stb[4]
231

232 233
        if       (read_format_byte) format_byte[7:0] <= format_data[7:0];
        else if (shift_format_byte) format_byte[7:0] <= {1'b0,format_byte[7:1]};
234

235 236 237 238 239 240
    //     format_byte[0] - current format
        if (stb[3]) last_byte[7:1] <= {ser_di,last_byte[7:2]};

        format_over   <=  stb[2] && wsep;

        sentence_over <=  stb[2] && (weof || w_sentence_over);
241
    
242
        if (bits37 && stb[3]) nibble_pre[3:0] <= last_byte[4:1]; // always OK
243
    
244 245 246 247 248 249
        if      (stb[3] && bit3)                             nibble[3:0] <= nibble_pre[3:0];
        else if (stb[3] && msb &&  wsep && (first_byte_in_field || !format_byte[0]))  nibble[3:0] <= 4'hf;
        else if (stb[3] && msb &&           format_byte[0])   nibble[3:0] <= {wsep,nibble_pre[2:0]};
        else if (save_sent_number) nibble[3:0] <= {2'b0,sentence[1:0]};
        
    //first_byte_in_field   
250
    
251 252
        extra_nibble[1:0] <= {extra_nibble[0],
                              msb &&  wsep && first_byte_in_field & proc_fields & stb[3] & format_byte[0]};// active at stb[4], stb[5]
253

254
        save_sent_number <= start_format; // valid at stb[4]
255

256 257 258 259
        nibble_stb <= save_sent_number ||
                        (proc_fields && ((stb[3] && bit3 && !first_byte_in_field) ||
                        (stb[3] && msb  && !first_byte_in_field && format_byte[0]) ||
                        (stb[3] && msb  && wsep))) || extra_nibble[1]; // extra_nibble[1] will repeat 4'hf
260
    
261 262 263 264 265
        if    (start_format) nibble_count[6:0] <= 7'h0;
        else if (nibble_stb) nibble_count[6:0] <= nibble_count[6:0] + 1;
        
        if (sentence_over) raddr[4:0] <= 5'h0;
        else if (rd_stb)    raddr[4:0] <= raddr[4:0] + 1;
266

267
        if (nibble_stb) last_word_written[4:0]<=nibble_count[6:2];
268

269 270
        if      (start || vfy_first_comma || (rd_stb && ((raddr[4:0]==5'h1b) ||(raddr[4:0]==last_word_written[4:0])))) rdy_r <= 1'b0;
        else if (sentence_over)   rdy_r <= 1'b1;
271

272 273 274 275 276 277 278 279 280 281 282 283
        nmea_sent_start <= start_char && vfy_dollar;
    end
// output buffer to hold up to 32 16-bit words. Written 1 nibble at a time
    // replaced 6 RAM modules with inferred ones
    reg     [3:0] odbuf0_ram[0:31];
    reg     [3:0] odbuf1_ram[0:31];
    reg     [3:0] odbuf2_ram[0:31];
    reg     [3:0] odbuf3_ram[0:31];
    always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h0)) odbuf0_ram[nibble_count[6:2]] <= nibble[3:0];
    always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h1)) odbuf1_ram[nibble_count[6:2]] <= nibble[3:0];
    always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h2)) odbuf2_ram[nibble_count[6:2]] <= nibble[3:0];
    always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h3)) odbuf3_ram[nibble_count[6:2]] <= nibble[3:0];
284

285 286 287 288
    assign rdata[ 3: 0] = odbuf0_ram[raddr[4:0]];
    assign rdata[ 7: 4] = odbuf1_ram[raddr[4:0]];
    assign rdata[11: 8] = odbuf2_ram[raddr[4:0]];
    assign rdata[15:12] = odbuf3_ram[raddr[4:0]];
289

290 291 292
    reg     [3:0] gpxxx_ram[0:3];
    always @ (posedge mclk) if (we &  ~wa[4]) gpxxx_ram[wa[3:0]] <= wd[3:0];
    assign gpxxx_w_one[3:0] =                 gpxxx_ram[gpxxx_addr[3:0]];
293 294 295 296
// for each of the four sentences first byte - number of field (<=24), next 3 bytes - formats for each nmea filed (LSB first):
// 0 - nibble ("-" -> 0xd, "." -> 0xe), terminated with 0xf
// 1 - byte (2 nibbles), all bytes but last have MSB clear, last - set.
// No padding of nibbles to byte borders, bytes are encoded as 2 nibbles
297 298 299 300
    reg     [7:0] format_ram[0:3];
    always @ (posedge mclk) if (we & wa[4]) format_ram[wa[3:0]] <= wd[7:0];
    assign format_data[7:0] =               format_ram[{sentence[1:0],format_field[4:3]}];

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
// ROM to decode "$GP"                     
  always @ (posedge xclk) begin
    if (ser_stb) case ({(bitnum[4] & ~ vfy_sel_sent) | vfy_first_comma, bitnum[3] | vfy_sel_sent | vfy_first_comma, bitnum[2:0]}) // during vfy_sel_sent will point to 1 ('G')
      5'h00:  gp_exp_bit <= 1'b0; //$
      5'h01:  gp_exp_bit <= 1'b0;
      5'h02:  gp_exp_bit <= 1'b1;
      5'h03:  gp_exp_bit <= 1'b0;
      5'h04:  gp_exp_bit <= 1'b0;
      5'h05:  gp_exp_bit <= 1'b1;
      5'h06:  gp_exp_bit <= 1'b0;
      5'h07:  gp_exp_bit <= 1'b0;
      5'h08:  gp_exp_bit <= 1'b1; //G
      5'h09:  gp_exp_bit <= 1'b1;
      5'h0a:  gp_exp_bit <= 1'b1;
      5'h0b:  gp_exp_bit <= 1'b0;
      5'h0c:  gp_exp_bit <= 1'b0;
      5'h0d:  gp_exp_bit <= 1'b0;
      5'h0e:  gp_exp_bit <= 1'b1;
      5'h0f:  gp_exp_bit <= 1'b0;
      5'h10:  gp_exp_bit <= 1'b0; //P
      5'h11:  gp_exp_bit <= 1'b0;
      5'h12:  gp_exp_bit <= 1'b0;
      5'h13:  gp_exp_bit <= 1'b0;
      5'h14:  gp_exp_bit <= 1'b1;
      5'h15:  gp_exp_bit <= 1'b0;
      5'h16:  gp_exp_bit <= 1'b1;
      5'h17:  gp_exp_bit <= 1'b0;
      5'h18:  gp_exp_bit <= 1'b0; //'h2c: "," - will use later - attach first comma to $GPxxx,
      5'h19:  gp_exp_bit <= 1'b0;
      5'h1a:  gp_exp_bit <= 1'b1;
      5'h1b:  gp_exp_bit <= 1'b1;
      5'h1c:  gp_exp_bit <= 1'b0;
      5'h1d:  gp_exp_bit <= 1'b1;
      5'h1e:  gp_exp_bit <= 1'b0;
      5'h1f:  gp_exp_bit <= 1'b0;
      default:gp_exp_bit <= 1'bX;
    endcase
  end
endmodule