nmea_decoder393.v 15.5 KB
Newer Older
1 2 3 4 5 6
/*******************************************************************************
 * Module: nmea_decoder393
 * Date:2015-07-06  
 * Author: andrey     
 * 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 20 21 22 23
 * 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/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  nmea_decoder393(
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    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);
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
    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;
91

92 93 94 95 96 97 98 99
    assign debug[23:0] =  {1'b0,
                           proc_fields,
                           vfy_first_comma,
                           vfy_sel_sent,
                           vfy_gp,
                           vfy_dollar,
                           bitnum[9:0],
                           debug0[7:0]};
100

101 102 103 104
    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));
105
  
106 107 108 109 110 111 112
    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;
    
113
//format_length_plus_7
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
    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];
174

175 176 177 178
        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]);
179

180 181 182 183 184 185 186 187 188
        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;
189
    
190 191 192 193 194 195
     
        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]));
196
    
197 198 199 200 201 202 203 204
        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;
205

206
        format_length_plus_7[4:0] <= format_length[4:0]+7;
207

208 209 210 211 212 213 214 215
        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]
216

217
        shift_format_byte <= format_over; // @stb[4]
218

219 220
        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]};
221

222 223 224 225 226 227
    //     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);
228
    
229
        if (bits37 && stb[3]) nibble_pre[3:0] <= last_byte[4:1]; // always OK
230
    
231 232 233 234 235 236
        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   
237
    
238 239
        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]
240

241
        save_sent_number <= start_format; // valid at stb[4]
242

243 244 245 246
        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
247
    
248 249 250 251 252
        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;
253

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

256 257
        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;
258

259 260 261 262 263 264 265 266 267 268 269 270
        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];
271

272 273 274 275
    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]];
276

277 278 279
    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]];
280 281 282 283
// 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
284 285 286 287
    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]}];

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
// 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