├── LICENSE ├── Makefile ├── README ├── build.mk ├── build_core.mk ├── cacode └── cacode.pl ├── doc └── GNSS_Baseband_UM.pdf ├── gpsif.vhm ├── gpsif_buf.vhm ├── gpsif_config_asic.vhd ├── gpsif_config_fpga.vhd ├── gpsif_config_sim.vhd ├── gpsif_db.vhm ├── gpsif_pkg.vhd ├── gpsif_reg.vhm ├── gpsif_sub_pkg.vhd ├── gpsif_time.vhm ├── gpsif_top.vhd ├── rbus_adp.vhm ├── rbus_pkg.vhd ├── tests ├── gpsif_db_tb.gtkw ├── gpsif_db_tb.vhd ├── gpsif_tb.gtkw ├── gpsif_tb.vhd ├── gpsif_tb_pkg.vhd ├── gpsob │ ├── Makefile_gpsob │ ├── README │ └── gpsif_tb_gpsob.vhd ├── input.txt ├── input2.txt └── output.golden └── tools ├── common.mk ├── ghdl.mk ├── tests ├── Makefile ├── runtests.c └── tap │ ├── basic.c │ ├── basic.h │ ├── libtap.sh │ ├── macros.h │ └── test_pkg.vhd └── v2p /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020, CoreSemi Pte Ltd. 2 | All rights reserved. 3 | 4 | Redistribution and use in source, binary, netlist or hardware instantiated 5 | forms, with or without modification, are permitted provided that the following 6 | conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VHDLS := VHDS 2 | include build.mk 3 | 4 | VHDS += tests/gpsif_tb.vhd 5 | VHDS += tests/gpsif_tb_pkg.vhd 6 | VHDS += tools/tests/tap/test_pkg.vhd 7 | 8 | VHDL_TESTS := gpsif_tb 9 | 10 | # if gpsif repo is inside the soc_top repo, pull in other vhdl files 11 | # and build gpsif_tb 12 | MK_UTILS := $(wildcard ../../tools/mk_utils.mk) 13 | ifeq ($(MK_UTILS),) 14 | MK_UTILS := $(wildcard ../tools/mk_utils.mk) 15 | include $(MK_UTILS) 16 | VHDS += $(call include_vhdl,../lib/reg_file_struct) 17 | endif 18 | MK_UTILS := $(wildcard ../../tools/mk_utils.mk) 19 | ifneq ($(MK_UTILS),) 20 | include $(MK_UTILS) 21 | VHDS += $(call include_vhdl,../cpu) 22 | VHDS += $(call include_vhdl,../ring_bus) 23 | VHDS += $(call include_vhdl,../../lib/fixed_dsm_pkg) 24 | VHDS += $(call include_vhdl,../../lib/reg_file_struct) 25 | VHDS += $(call include_vhdl,../../lib/memory_tech_lib) 26 | VHDS += $(call include_vhdl,../../lib/hwutils) 27 | endif 28 | 29 | VHDL_TOPS += $(VHDL_TESTS) 30 | 31 | TOOLS_DIR := $(firstword $(wildcard ../../tools) tools) 32 | 33 | all: $(VHDL_TOPS) 34 | 35 | work-obj93.cf: $(VHDS) 36 | 37 | tests/gpsif_tb.ghw: gpsif_tb 38 | ./gpsif_tb --wave=$@ --stop-time=9400us --ieee-asserts=disable 39 | 40 | RUNTESTS := $(TOOLS_DIR)/tests/runtests 41 | $(RUNTESTS): 42 | make -C $(dir $@) 43 | 44 | check: $(RUNTESTS) $(VHDL_TESTS) 45 | $(RUNTESTS) test_bins 46 | 47 | tap: $(RUNTESTS) $(VHDL_TESTS) 48 | $(RUNTESTS) -t test_bins 49 | 50 | include $(TOOLS_DIR)/ghdl.mk 51 | 52 | clean: 53 | rm -f *.cf *.o $(VHDL_TOPS) *_tap tests/*.ghw 54 | rm -f gpsif.vhd gpsif_reg.vhd cacode.vhd gpsif_db.vhd gpsif_buf.vhd rbus_adp.vhd 55 | make -C $(dir $(RUNTESTS)) clean 56 | 57 | .PHONY: all clean check tap 58 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | CoreSemi GNSS Baseband receiver for GPS compatible signals. 2 | 3 | See the manual "1v0 GPS Manual" for details. 4 | 5 | -------------------------------------------------------------------------------- /build.mk: -------------------------------------------------------------------------------- 1 | include $(dir $(lastword $(MAKEFILE_LIST)))build_core.mk 2 | 3 | $(VHDLS) += gpsif_config_fpga.vhd 4 | $(VHDLS) += gpsif_config_sim.vhd 5 | -------------------------------------------------------------------------------- /build_core.mk: -------------------------------------------------------------------------------- 1 | $(VHDLS) += rbus_pkg.vhd 2 | $(VHDLS) += rbus_adp.vhd 3 | $(VHDLS) += gpsif_pkg.vhd 4 | $(VHDLS) += gpsif_sub_pkg.vhd 5 | $(VHDLS) += gpsif.vhd 6 | $(VHDLS) += gpsif_reg.vhd 7 | $(VHDLS) += gpsif_db.vhd 8 | $(VHDLS) += gpsif_buf.vhd 9 | $(VHDLS) += gpsif_time.vhd 10 | $(VHDLS) += gpsif_top.vhd 11 | -------------------------------------------------------------------------------- /cacode/cacode.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | 3 | $prn = $ARGV[0]; 4 | 5 | $str; 6 | 7 | @g2shift = ( 5, 6, 7, 8, 17, 18, 139, 140, 141, 251, 252, 254, 255, 256, 257, 258, 469, 470, 471, 472, 473, 474, 509, 512, 513, 514, 515, 516, 859, 860, 861, 862, 145, 175, 52, 21, 237, 235, 886, 657, 634, 762, 355, 1012, 176, 603, 130, 359, 595, 68, 386); 8 | @g = (-1,-1,-1,-1,-1,-1,-1,-1,-1,-1); 9 | 10 | for ($i=0; $i<1023; $i++){ 11 | if(($i >= 1023- $g2shift[$prn-1] -1) and ($i < 1023- $g2shift[$prn-1] +10-1)){ 12 | if($g[9] == 1){ 13 | printf "0"; 14 | $str = "0".$str; 15 | }else{ 16 | printf "1"; 17 | $str = "1".$str; 18 | } 19 | } 20 | 21 | $tmp = 0; 22 | for ($j=9;$j>=0;$j--){ 23 | $tmp = $tmp*2; 24 | if($g[$j] == -1){ 25 | $tmp = $tmp +1; 26 | } 27 | } 28 | printf " %03x %04o\n",$tmp,$tmp; 29 | 30 | #G1 31 | # $tmp = $g[2]*$g[9]; 32 | #G2 33 | $tmp = $g[1]*$g[2]*$g[5]*$g[7]*$g[8]*$g[9]; 34 | 35 | for ($j=9;$j>0;$j--){ 36 | $g[$j] = $g[$j-1]; 37 | } 38 | $g[0] = $tmp; 39 | # print " @g\n"; 40 | } 41 | print "\n"; 42 | #print "$str\n"; 43 | $str = "00".$str; 44 | $str = unpack("H3", pack("B*", $str)); 45 | printf "$str\n"; 46 | -------------------------------------------------------------------------------- /doc/GNSS_Baseband_UM.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoreSemi/gnss-baseband/42f19080aeeaa6946508fe7b70cd8b1a879ea8cb/doc/GNSS_Baseband_UM.pdf -------------------------------------------------------------------------------- /gpsif.vhm: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.fixed_pkg.all; 6 | use work.rf_pack.all; 7 | use work.memory_pack.all; 8 | use work.bist_pack.all; 9 | use work.ring_bus_pack.all; 10 | use work.rbus_pack.all; 11 | use work.cpu2j0_pack.all; 12 | use work.gpsif_pack.all; 13 | use work.gpsif_sub_pack.all; 14 | 15 | entity gpsif is 16 | generic ( GPSIF_NC : integer := 7; 17 | ANGLE_INI_OLD : boolean := false ); 18 | port ( 19 | clk : in std_logic; 20 | rst : in std_logic; 21 | bi : in bist_scan_t; 22 | bo : out bist_scan_t; 23 | -- for debug on FPGA (from here) 24 | ring_i : in rbus_9b; -- to monitor ring bus 25 | ring_o : in rbus_9b; -- to monitor ring bus 26 | -- for debug on FPGA (to here) 27 | tgt_o : out cpu_data_i_t; 28 | tgt_i : in gpsif_tgt_i_t; 29 | dev_o : out rbus_dev_o_t; 30 | dev_i : in rbus_dev_i_t; 31 | buf_io : in gpsif_buf_i_t; 32 | time_i : in gpsif_time_t; 33 | ra_io : out gpsif_buf_ct_t; 34 | buf_bus : in gpsif_i_t; 35 | gpsif_o : out gpsif_o_t; 36 | dma : out dma_req_t ); 37 | end gpsif; 38 | 39 | architecture beh of gpsif is 40 | 41 | register variable this : gpsif_reg_t reset := GPSIF_REG_RESET; 42 | 43 | signal regfile_i : gpsif_regfile_i_t; 44 | signal regfile_o : gpsif_regfile_o_t; 45 | -- for debug on FPGA (from here) 46 | type dbg_d_t is array (integer range 0 to 2) of std_logic_vector(31 downto 0); 47 | signal dbg_w : std_logic; 48 | signal dbg_a : std_logic_vector( 7 downto 0); 49 | signal dbg_wd,dbg_rd : dbg_d_t; 50 | 51 | begin 52 | dbg0h : ram_1rw 53 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 54 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(0)(31 downto 16), 55 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(0)(31 downto 16)); 56 | dbg0l : ram_1rw 57 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 58 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(0)(15 downto 0), 59 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(0)(15 downto 0)); 60 | dbg1h : ram_1rw 61 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 62 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(1)(31 downto 16), 63 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(1)(31 downto 16)); 64 | dbg1l : ram_1rw 65 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 66 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(1)(15 downto 0), 67 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(1)(15 downto 0)); 68 | dbg2h : ram_1rw 69 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 70 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(2)(31 downto 16), 71 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(2)(31 downto 16)); 72 | dbg2l : ram_1rw 73 | generic map ( SUBWORD_WIDTH => 8, SUBWORD_NUM => 2, ADDR_WIDTH => 8 ) 74 | port map ( clk => clk, en => '1', we => "11", a => dbg_a, dw => dbg_wd(2)(15 downto 0), 75 | rst => rst, wr => dbg_w, margin => "00", dr => dbg_rd(2)(15 downto 0)); 76 | -- for debug on FPGA (to here) 77 | 78 | regfile : gpsif_regfile port map ( rst => rst, clk => clk, bi => bi, bo => bo, a => regfile_i, y => regfile_o); 79 | 80 | p0 : process(this, buf_io, buf_bus, tgt_i, dev_i, time_i, regfile_o, ring_i, ring_o) 81 | register this when clk = '1' and clk'event reset sync when rst = '1'; 82 | variable active, acm_lst, acm_done, acm_strt, acm_now, acm_nxt, sft_we, stall, mns_inc : boolean; 83 | variable cntl : gpsif_cntl_t; 84 | variable carrmix_i : gpsif_carrmix_i_t; 85 | variable carrmix_o : gpsif_carrmix_o_t; 86 | variable angle, delta : gpsif_angle_t; 87 | variable delta_slv : std_logic_vector(delta'range); 88 | variable next_cnt1ms : ufixed(gpsif_cnt1ms_t'high+1 downto 0); 89 | variable next_ch : gpsif_ch_t; 90 | variable rbus_ch : integer range 0 to GPSIF_NC_MAX; 91 | variable wbus_ch : integer range 0 to GPSIF_NC_MAX; 92 | variable nn_ch : integer range 0 to GPSIF_NC_MAX; 93 | variable n_ch : integer range 0 to GPSIF_NC_MAX; 94 | variable ch : integer range 0 to GPSIF_NC_MAX; 95 | variable ra_range : natural range 64 to GPSIF_RW_MAX+1; 96 | variable nd_range : natural range 4 to GPSIF_ND_MAX+1; 97 | variable wa : integer range 0 to GPSIF_ND_MAX; 98 | variable carrmix : gpsif_sum_t; 99 | variable sum : gpsif_sum_d_t; 100 | variable acm : gpsif_acm_d_t; 101 | variable code, g1sft0, g2sft0 : std_logic; 102 | variable sft_chg : gpsif_sft_chg_t; 103 | variable sft_1ms : gpsif_cnt1ms_t; 104 | variable sft_now : gpsif_sft_t; 105 | variable sft_tmp_h : ufixed(sft_now'high -5 downto 0); -- to absorb carry 106 | variable sft_nxt_h : ufixed(sft_now'high -6 downto 0); 107 | constant sft_dec_h : ufixed(sft_now'high -6 downto 0) := (others => '1'); 108 | variable sft_nxt_l : ufixed(6 downto 0); -- to absorb carry 109 | variable sft_inc : integer range 1 to 63; 110 | variable pnco_now : ufixed(delta'high-10 downto 0); 111 | variable pnco_nxt : ufixed(pnco_now'high+1 downto pnco_now'low); -- to absorb carry 112 | variable pnco_inc : natural range 1 to 256; 113 | variable reg_i : gpsif_regfile_i_t; 114 | variable devo : rbus_dev_o_t; 115 | variable tgt_rd : std_logic_vector(31 downto 0); 116 | 117 | -- for debug on FPGA (from here) 118 | variable dbg_b,dbg_r,dbg_v : boolean; -- 1ms boundary, CPU read debug info., dump debug info. 119 | variable dbg_i,dbg_q : gpsif_sum_d_t; 120 | -- for debug on FPGA (to here) 121 | 122 | begin 123 | -- select input source, and set up parameters 124 | case this.src is 125 | when IO_PIN => 126 | carrmix_i.d := buf_io.d; wa := buf_io.wa; ra_range := 64; nd_range := 4; 127 | when CPU_BUS => 128 | carrmix_i.d := buf_bus.d; wa := buf_bus.wa; ra_range := GPSIF_RW_MAX+1; nd_range := GPSIF_ND_MAX+1; 129 | when others => -- ((BITL_BUS1 or BITL_BUS2) 130 | carrmix_i.d := time_i.d; wa := time_i.wa; ra_range := 64; nd_range := 4; 131 | end case; 132 | if GPSIF_NC = 7 then 133 | -- channel update with 3b LFSR (only two ENOR gates for next & next-next channel numbers) 134 | -- 000 -> 001 -> 011 -> 110 -> 101 -> 010 -> 100 135 | next_ch := this.ch(1) & this.ch(0) & not (this.ch(2) xor this.ch(1)); 136 | nn_ch := vtoui(next_ch(1) & next_ch(0) & not (next_ch(2) xor next_ch(1))); 137 | n_ch := vtoui(next_ch); 138 | else -- use incrementer for arbitary GPSIF_NC (1 to 6) 139 | n_ch :=(vtoui(this.ch)+1) mod GPSIF_NC; 140 | nn_ch := (n_ch +1) mod GPSIF_NC; 141 | next_ch := itov(n_ch, next_ch'length); 142 | end if; 143 | ch := vtoui(this.ch); 144 | 145 | if this.sft.chg = MNS and this.scp_chg then nn_ch := n_ch; end if; 146 | if this.sft.typ = AGN then nn_ch := n_ch; n_ch := ch; end if; 147 | active := this.ready and this.st(n_ch).run and 148 | not(this.scp_chg and this.sft.chg = PLS); -- skip for scope change 149 | acm_lst:= this.st(n_ch).mode(2 downto 1) /= "00" and this.ready and this.bndry; 150 | -- Accumulate for 1ms with C/A code -------------------------------------------- 151 | reg_i.acm.a := ch * (GPSIF_REG_PER_CH/2); -- not to add rd for 6,7 to avoid boudary check error 152 | case this.rd is 153 | when 6 => reg_i.sftca.ra := n_ch; 154 | when 7 => reg_i.sftca.ra := nn_ch + (GPSIF_NC_MAX + 1); 155 | when others => reg_i.sftca.ra := ch + (GPSIF_NC_MAX + 1); 156 | reg_i.acm.a := reg_i.acm.a + this.rd/2; 157 | end case; 158 | reg_i.sftca.wa := reg_i.sftca.ra; -- ra & wa are the same for internal operations 159 | if this.rd mod 2 = 0 then 160 | reg_i.acm.bs := '0'; sum := this.sum.i; -- I 161 | else reg_i.acm.bs := '1'; sum := this.sum.q; -- Q 162 | end if; 163 | case this.rd is 164 | when 0 | 1 => code := this.code(2); -- E 165 | when 2 | 3 => code := this.code(1); -- P 166 | when others => code := this.code(0); -- L 167 | end case; 168 | if code = '1' then acm := vtoi(regfile_o.acm) + sum; 169 | else acm := vtoi(regfile_o.acm) - sum; 170 | end if; 171 | if this.acm_lst then 172 | reg_i.acm.wd := (others => '0'); 173 | else reg_i.acm.wd := itov(acm,GPSIF_ACMREG_MAX+1); end if; 174 | reg_i.buf.wd := itov(acm,GPSIF_ACMREG_MAX+1); 175 | case this.rd is 176 | when 6 | 7 => acm_nxt := false; 177 | acm_now := false; 178 | when others => acm_nxt := this.ready and this.acm_lst; 179 | acm_now := this.ready and (this.acm_lst or this.acm_en); 180 | end case; 181 | if acm_nxt then reg_i.buf.we := '1'; else reg_i.buf.we := '0'; end if; 182 | if acm_now then reg_i.acm.we := '1'; else reg_i.acm.we := '0'; end if; 183 | -- RING bus -------------------------------------------------------------------- 184 | -- Assuming bus is always available, 185 | -- output signals are generated without response from the bus. 186 | -- The first data is used at the 3rd cycle. (cmd and ch are output at 1st and 2nd cycles) 187 | -- keep devo.v true while sending. (BUSY insersion is another way.) 188 | case this.rd is 189 | when 2 | 6 => devo.d := itov(this.sum.i, 9); -- lower 9 bits 190 | when 3 | 7 => devo.d := itov(this.sum.i,18)(17 downto 9); -- higher bits w/ sign ext. 191 | when 4 | 0 => devo.d := itov(this.sum.q, 9); 192 | when 5 | 1 => devo.d := itov(this.sum.q,18)(17 downto 9); 193 | end case; 194 | devo.v := false; 195 | if this.ready and this.st(ch).mode(2 downto 1) = "01" and this.st(ch).run then case this.rd is -- ACQ 196 | when 0 | 1 | 2 | 3 | 4 | 5 => devo.v := true; 197 | when others => 198 | end case; end if; 199 | devo.bsy := false; -- Currently, fixed to false (currently not used) 200 | devo.ch := RNG_CH_DSP; -- Currently, fixed to DSP 201 | -- Carrier NCO Multply & Accumulate for 8 cycles-------------------------------- 202 | delta := to_ufixed(regfile_o.pnco, gpsif_angle_t'high,gpsif_angle_t'low); 203 | angle := to_ufixed(regfile_o.angle,gpsif_angle_t'high,gpsif_angle_t'low); 204 | carrmix_i.angle := angle(GPSIF_ANGLE_BITS-1 downto GPSIF_ANGLE_BITS-GPSIF_ANGLE_INDX); 205 | carrmix_o := gpsif_carrmix(carrmix_i); 206 | if active then case this.rd is 207 | when 0 => this.add.i := carrmix_o.i; 208 | this.add.q := carrmix_o.q; 209 | when 7 => this.sum.i := carrmix_o.i + this.add.i; -- update after use 210 | this.sum.q := carrmix_o.q + this.add.q; 211 | when others => this.add.i := carrmix_o.i + this.add.i; 212 | this.add.q := carrmix_o.q + this.add.q; end case; 213 | reg_i.angle.we := '1'; 214 | else reg_i.angle.we := '0'; 215 | end if; 216 | reg_i.pnco.a := n_ch; 217 | reg_i.angle.a := n_ch; 218 | reg_i.angle.wd := to_slv(resize(angle + delta, gpsif_angle_t'high, gpsif_angle_t'low)); 219 | -- PNCO update data (It is not always used, but must be defined to avoide inferred latch) 220 | reg_i.pnco.wd := regfile_o.pnco; -- to make LS 9 bits unchanged (It is fit to current TB) 221 | --reg_i.pnco.wd := (others => '0'); -- Zero clear is enough to scan. 222 | case this.inc.pnco is 223 | when "000" => pnco_inc := 1; -- 8Hz (7.8048) 224 | when "001" => pnco_inc := 2; -- 16Hz (15.6096) 225 | when "010" => pnco_inc := 4; -- 31Hz (31.2192) 226 | when "011" => pnco_inc := 8; -- 62Hz (62.4384) 227 | when "100" => pnco_inc := 16; -- 125Hz (124.9) 228 | when "101" => pnco_inc := 32; -- 250Hz (249.8) 229 | when "110" => pnco_inc := 64; -- 500Hz (499.5) 230 | when "111" => pnco_inc := 128; -- 1 KHz (999) 231 | when others => 232 | end case; 233 | if regfile_o.pnco(20 downto 19) & regfile_o.pnco(17) = "011" then -- PNCO is +10kHz 234 | reg_i.pnco.wd(delta'high-1 downto delta'low+17) := X"7fb"; -- rwind to -10kHz 235 | else pnco_now := delta(delta'high-1 downto delta'low+9); 236 | pnco_nxt := pnco_now + pnco_inc; 237 | reg_i.pnco.wd(delta'high-1 downto delta'low+9) := to_slv(pnco_nxt(pnco_now'range)); 238 | end if; 239 | -- C/A code upfdate at RD = 6 for next RD period of 8 cycles-------------------- 240 | g1sft0 := regfile_o.sftca(19) xor regfile_o.sftca(12); 241 | g2sft0 := regfile_o.sftca( 9) xor regfile_o.sftca( 8) xor regfile_o.sftca(7) xor 242 | regfile_o.sftca( 5) xor regfile_o.sftca( 2) xor regfile_o.sftca(1); 243 | reg_i.sftca.wd := regfile_o.sftca(18 downto 10) & g1sft0 & 244 | regfile_o.sftca( 8 downto 0) & g2sft0; 245 | reg_i.sftca.we := '0'; 246 | if this.rd = 6 and active then 247 | this.code(2) := regfile_o.sftca(19) xor regfile_o.sftca(9); 248 | this.code(0) := regfile_o.sftca(18) xor regfile_o.sftca(8); 249 | -- 2 * 1.023 MHz sample CA code ganeration 250 | if this.even then this.code(1) := this.code(2); 251 | else reg_i.sftca.we := '1'; this.code(1) := this.code(0); end if; 252 | end if; 253 | 254 | if((this.cnt1ms(10) = '0') and (this.cnt1ms(9) = '1')) or 255 | ( this.inittm(1) = '1') then 256 | this.inittm := "10"; -- suppress 2nd init command 257 | elsif(std_logic_vector(this.cnt1ms) = "000" & x"20") and 258 | (this.inittm(1) = '0') then 259 | -- synchronize gps_tm 260 | this.inittm := "01"; 261 | else this.inittm := "00"; -- keep 262 | end if; 263 | 264 | -- Next states ----------------------------------------------------------------- 265 | -- range of cnt1ms is 0 to 2045 (skip 2046,2047) 266 | -- Increment higher bits (other than lower 2 bits) every 4 ND+CH periods, but 2 periods for 2044/4 to skip the 2046,2047. 267 | next_cnt1ms := this.cnt1ms + 4; 268 | -- Channel State transition w/ checking 1 ms period (before 1ms counter update) 269 | -- IDL: Channel is idle. 270 | -- ACQ: Channel is Acquisition. (send carrier mix data to DSP) 271 | -- RDY: Channel is Tracking. 272 | -- VLD: Channel is Tracking, and result is valid. 273 | acm_done := false; -- default 274 | acm_strt := false; -- default 275 | cntl := (vld => '0', ovr => '0', others => false); -- default 276 | case this.rd is 277 | when 5 => acm_done := this.ready and this.acm_lst and this.acm_en; 278 | when 7 => acm_strt := this.ready and this.acm_lst; 279 | when others => 280 | end case; 281 | this.dma_req(this.dma_req'high) := '0'; -- default 282 | if acm_done and this.st(ch).run and this.st(ch).mode(2) = '1' then -- TRK 283 | this.dma_req := '1' & regfile_o.sftca(19 downto 14); 284 | case this.odd_ms is 285 | when 1 => this.st(ch).mode(1) := '1'; cntl.vld := '1'; cntl.ovr := this.st(ch).mode(0); -- VLD in odd period 286 | when 0 => this.st(ch).mode(0) := '1'; cntl.vld := '1'; cntl.ovr := this.st(ch).mode(1); -- VLD in even period 287 | end case; end if; 288 | if acm_strt and this.st(ch).mode(2 downto 1) /= "00" then this.st(ch).run := true; end if; 289 | -- Count-up speed of nd and cnt1ms are the same, but cnt1ms skips 2046 and 2047 to count 0 to 2045 (not 2047). 290 | reg_i.pnco.we := '0'; 291 | stall := false; 292 | sft_now := to_ufixed(regfile_o.sftca(sft_now'range),sft_now'high,sft_now'low); 293 | sft_1ms := sft_now(sft_now'high downto sft_now'high - gpsif_cnt1ms_t'high); 294 | if this.ready then 295 | if this.rd = GPSIF_RD_MAX then 296 | this.acm_en := active; -- Skip is done by controlling state (Clearing acm_en is not enough) 297 | this.acm_lst := acm_lst; 298 | -- Next channel 299 | -- Do extra channel processing if the same scope is to be used for sft -1 correction. 300 | -- register output is not for the extra, it is already for next channel. 301 | if this.sft.typ /= AGN then this.ch := next_ch; end if; -- use current AGN 302 | if this.sft.typ = SKP then this.st(ch).run := false; end if; 303 | this.sft.typ := NOP; 304 | case this.sft.chg is 305 | when INC => if this.scp_chg then this.sft.typ := SKP; end if; 306 | when MNS => if this.scp_chg then this.sft.typ := AGN; end if; reg_i.angle.we := '0'; -- Do next channel twice 307 | when others => 308 | end case; 309 | if this.sft.typ /= AGN and this.ch = GPSIF_NC_END then -- use next AGN 310 | if this.nd mod 2 = 1 then this.sft.ext := false; end if; -- clear every 2 ND processing 311 | this.nd := (this.nd + 1) mod nd_range; -- update input data scope 312 | if((next_cnt1ms(next_cnt1ms'high) or this.cnt1ms(1)) and this.cnt1ms(0)) = '1' then 313 | this.cnt1ms(this.cnt1ms'high downto 2) := 314 | next_cnt1ms(this.cnt1ms'high downto 2); end if; 315 | this.cnt1ms(1 downto 0) := ((this.cnt1ms(1) xor this.cnt1ms(0)) and not next_cnt1ms(next_cnt1ms'high)) & not this.cnt1ms(0); 316 | cntl.bndry := (next_cnt1ms(next_cnt1ms'high) and this'register.cnt1ms(0)) = '1'; 317 | -- for DEBUG (from here) 318 | if cntl.bndry and this.odd_ms = 1 then this.dbg2ms := (this.dbg2ms + 1) mod (DBG_2MS_MAX+1); end if; -- count 2ms 319 | -- for DEBUG (to here) 320 | if cntl.bndry then this.odd_ms := 1 - this.odd_ms; end if; end if; 321 | -- sft_now is used here for the current input scope. 322 | this.bndry := this.cnt1ms = sft_1ms; 323 | this.even := this.cnt1ms(0) = sft_1ms(0); 324 | this.ra := (this.nd * 8 + to_integer(sft_now(2 downto 0))) mod ra_range; -- use next nd 325 | -- Update sft & check input scope change 326 | -- Note: Logic can be simpler by removing INC 1,4, further by removing minus INC logic 327 | sft_we := false; sft_inc := 1; mns_inc := false; -- default 328 | case this.st(nn_ch).sft is 329 | when INC => if this.bndry then -- for serial acquisition 330 | case this.inc.sft is 331 | when "100" => sft_inc := 4; 332 | when "001" => sft_inc := 8; 333 | when "010" => sft_inc := 16; 334 | when "011" => sft_inc := 24; 335 | when "101" => sft_inc := 64 - 24; mns_inc := true; 336 | when "110" => sft_inc := 64 - 16; mns_inc := true; 337 | when "111" => sft_inc := 64 - 8; mns_inc := true; 338 | when others => 339 | end case; sft_we := true; end if; 340 | when PLS => sft_we := true; 341 | when MNS => sft_we := true; sft_inc := 64 - 1; mns_inc := true; 342 | when others => 343 | end case; 344 | sft_nxt_h := sft_now(sft_now'high downto 6); 345 | sft_nxt_l := sft_now(5 downto 0) + sft_inc; 346 | if mns_inc then 347 | sft_tmp_h := sft_nxt_h + sft_dec_h; 348 | if sft_nxt_l(6) = '0' then sft_nxt_h := sft_tmp_h(sft_nxt_h'range); -- change higher part 349 | if sft_tmp_h(sft_tmp_h'high) = '0' then sft_nxt_l := sft_nxt_l(5 downto 0) - 16; end if; end if; -- skip 1023 (2b dec.) 350 | else sft_tmp_h := sft_nxt_h + 1; 351 | if ((sft_tmp_h(sft_tmp_h'high) and sft_nxt_l(5) and sft_nxt_l(4)) or sft_nxt_l(6)) = '1' 352 | then sft_nxt_h := sft_tmp_h(sft_nxt_h'range); -- change higher part 353 | if sft_tmp_h(sft_tmp_h'high) = '1' then sft_nxt_l := sft_nxt_l(5 downto 0) + 16; end if; end if; -- skip 1023 (2b inc.) 354 | end if; 355 | this.scp_chg := sft_nxt_l(5 downto 3) /= sft_now(5 downto 3) and sft_we; 356 | -- Only one extra processing per 7*2 8-cycle is possible. (10 < (125000/1023 - 8*7*2) < 11) 357 | -- Postpone extra processing if another extra processing is already done. 358 | this.sft.chg := NOP; -- defaut 359 | if sft_we then case this.st(nn_ch).sft is 360 | when INC => this.sft.chg := INC; 361 | when PLS => stall := true; this.sft.chg := PLS; 362 | when MNS => if not (this.sft.ext and this.scp_chg) then this.sft.chg := MNS; 363 | this.sft.ext := this.scp_chg or this.sft.ext; 364 | else sft_we := false; end if; 365 | when others => 366 | end case; end if; 367 | -- Clear sft state if new sft is written. 368 | if sft_we then reg_i.sftca.we := '1'; this.st(nn_ch).sft := NOP; end if; 369 | reg_i.sftca.wd := regfile_o.sftca; -- This is necessary to keep dma info as is. 370 | reg_i.sftca.wd(sft_now'range) := to_slv(sft_nxt_h) & to_slv(sft_nxt_l(5 downto 0)); 371 | -- Update PNCO 372 | if this.st(n_ch).pnco and this.acm_lst then 373 | this.st(n_ch).pnco := false; 374 | reg_i.pnco.we := '1'; 375 | reg_i.angle.we := '1'; 376 | if ANGLE_INI_OLD then reg_i.angle.wd := reg_i.pnco.wd; -- Angle should be pnco here for old expected values. 377 | else reg_i.angle.wd := (others => '0'); end if; 378 | end if; 379 | else this.ra := (this.ra + 1) mod ra_range; end if; 380 | this.rd := (this.rd + 1) mod 8; 381 | elsif this.sft.chg = PLS then reg_i.angle.we := '1'; end if; -- update during inserted stall 382 | -- Is input data ready ? ------------------------------------------------------- 383 | this.ready := not stall and (wa /= ((this.nd +1) mod nd_range)); -- use next nd 384 | -- Write pointer wrap round is limited at the last ND states 385 | -- to avoid overwriting of unused data 386 | -- This is only for CPU bus input that can be faster than the gpsif. 387 | -- Direct input never overwrite unused data. 388 | cntl.lst := this.nd = GPSIF_ND_MAX; -- use next nd 389 | -- CPU bus --------------------------------------------------------------------- 390 | dbg_r := false; -- defaut (It becomes true if CPU read the debug info. Then the pointer is updated.) 391 | delta_slv := '0' & not tgt_i.d(delta'high-1) 392 | & tgt_i.d(delta'high-2 downto 0); 393 | reg_i.sftca_obs.ra := vtoui(tgt_i.a(5 downto 2) and ("11" & not to_bit(tgt_i.a(5 downto 4) = "11") & "1")); -- cdef -> cd to avoid out of range 394 | wbus_ch := vtoui(tgt_i.a(4 downto 2)); 395 | rbus_ch := vtoui(tgt_i.a(7 downto 5) and ("11" & not to_bit(tgt_i.a(7 downto 6) = "11"))); -- 67 -> 6 396 | reg_i.buf.a := rbus_ch*3 +(vtoui(tgt_i.a(4 downto 3) and ( "1" & not tgt_i.a(4) ))); -- 23 -> 2 397 | reg_i.buf.bs := tgt_i.a(2); 398 | 399 | this.ack := '0'; -- defaut for no bus operation 400 | if tgt_i.en = '1' and this'register.ack = '0' then this.ack := '1'; -- defaut for bus operation 401 | if tgt_i.wr = '1' then -- reg write 402 | case tgt_i.a(8 downto 5) is 403 | when b"00_00" => if tgt_i.d(tgt_i.d'high) = '0' then 404 | if reg_i.sftca.we = '1' then this.ack := '0'; -- delay to avoid port conflict 405 | else reg_i.sftca.we := '1'; 406 | reg_i.sftca.wd := tgt_i.d(gpsif_sftca_reg_t'range); 407 | reg_i.sftca.wa := wbus_ch + (GPSIF_NC_MAX + 1); end if; 408 | end if; 409 | sft_chg := gpsif_sft_chg_t'val(vtoui(tgt_i.d(gpsif_sft_fld_t'range))); 410 | if sft_chg /= NOP then this.st(wbus_ch).sft := sft_chg; end if; 411 | if tgt_i.d(gpsif_sft_fld_t'low -1) = '1' then this.st(wbus_ch).pnco := true; end if; 412 | if tgt_i.d(gpsif_sft_inc_t'high+1) = '1' then this.inc.sft := tgt_i.d(gpsif_sft_inc_t'range); end if; 413 | if tgt_i.d(gpsif_pncoinc_t'high+1) = '1' then this.inc.pnco := tgt_i.d(gpsif_pncoinc_t'range); end if; 414 | when b"00_01" => if reg_i.sftca.we = '1' then this.ack := '0'; -- delay to avoid port conflict 415 | else reg_i.sftca.we := '1'; 416 | reg_i.sftca.wd := "0111111111" & tgt_i.d(9 downto 0); 417 | reg_i.sftca.wa := wbus_ch; 418 | if tgt_i.d(31) = '1' then this.st(wbus_ch).mode := "010"; -- ACQ 419 | else this.st(wbus_ch).mode := "100"; end if; -- TRK 420 | this.st(wbus_ch).run := false; end if; 421 | when b"00_10" => if reg_i.pnco.we = '1' then this.ack := '0'; -- delay to avoid port conflict 422 | else reg_i.pnco.we := '1'; 423 | reg_i.pnco.wd := delta_slv; 424 | reg_i.pnco.a := wbus_ch; 425 | -- The angle can be any value at init., but must be "delta" for the old expected values. 426 | if this'register.st(wbus_ch).mode(2 downto 1) = "00" then -- IDL 427 | reg_i.angle.a := wbus_ch; 428 | reg_i.angle.we := '1'; 429 | if ANGLE_INI_OLD then reg_i.angle.wd := delta_slv; 430 | else reg_i.angle.wd := (others => '0'); end if; end if; end if; 431 | when b"00_11" => if tgt_i.d(31) = '0' then this.rst_en := true; 432 | if tgt_i.d(1 downto 0) = "00" then this.src := IO_PIN; -- input from IO pin 433 | elsif tgt_i.d(1 downto 0) = "01" then this.src := CPU_BUS; -- input from CPU bus 434 | elsif tgt_i.d(1 downto 0) = "10" and tgt_i.d(8) = '0' then this.src := BITL_BUS2; -- input from BL(2b/spl) bus 435 | elsif tgt_i.d(1 downto 0) = "10" and tgt_i.d(8) = '1' then this.src := BITL_BUS1; end if; -- input from BL(1b/spl) bus 436 | end if; 437 | this.int_en := tgt_i.d(5 downto 2); 438 | -- for debug on FPGA (from here) 439 | if tgt_i.d(30) = '1' then -- debug enabled 440 | this.dbg_strt := vtoui(tgt_i.d(29 downto 6)); 441 | this.dbg_st := DBG_RDY; 442 | end if; 443 | -- for debug on FPGA (to here) 444 | when others => 445 | end case; 446 | else -- reg read 447 | -- Clear valid flag after read. 448 | if tgt_i.a(8) = '1' and tgt_i.a(4 downto 2) = "101" then 449 | if this.st(rbus_ch).mode(1 downto 0) = "11" then cntl.err := true; end if; 450 | this.st(rbus_ch).mode(1 downto 0) := "00"; end if; -- clear VLD 451 | end if; -- tgt_i.wr 452 | end if; 453 | if tgt_i.a(8) = '1' then 454 | if tgt_i.a(9) = '0' then -- 0x100-1fc 455 | tgt_rd := (others => regfile_o.buf(regfile_o.buf'high)); -- signed 456 | tgt_rd(regfile_o.buf'range) := regfile_o.buf; 457 | else -- --------------- -- 0x300-3fc 458 | tgt_rd := (others => '0'); -- unsigned -- || 0x300 459 | tgt_rd(regfile_o.sftca_obsv'range) := regfile_o.sftca_obsv; -- || 0x300 460 | end if; 461 | -- for debug on FPGA (from here) 462 | else case tgt_i.a(6 downto 5) is -- read dumped signals 463 | when "00" => tgt_rd := dbg_rd(0); 464 | when "01" => tgt_rd := dbg_rd(1); 465 | when "10" => tgt_rd := dbg_rd(2); dbg_r := this.ack = '1'; 466 | when others => 467 | end case; 468 | -- for debug on FPGA (to here) 469 | end if; 470 | 471 | -- Reset ----------------------------------------------------------------------- 472 | if this'register.rst_en then this := GPSIF_REG_RESET; 473 | this.int_en := this'register.int_en; 474 | -- for debug on FPGA (from here) 475 | this.dbg_st := this'register.dbg_st; 476 | this.dbg_strt := this'register.dbg_strt; 477 | -- for debug on FPGA (to here) 478 | if this'register.src = CPU_BUS then this.src := CPU_BUS; end if;-- input from CPU bus 479 | if this'register.src = BITL_BUS1 then this.src := BITL_BUS1; end if;-- input from BL(1b) 480 | if this'register.src = BITL_BUS2 then this.src := BITL_BUS2; end if;-- input from BL(2b) 481 | end if; 482 | -------------------------------------------------------------------------------- 483 | -- connect output 484 | gpsif_o.cntl <= cntl; 485 | gpsif_o.odd <= this.odd_ms = 1; -- output before latch 486 | gpsif_o.rst <= this'register.rst_en; 487 | gpsif_o.sr <= this'register.st(6).mode(1 downto 0) 488 | & this'register.st(5).mode(1 downto 0) 489 | & this'register.st(4).mode(1 downto 0) 490 | & this'register.st(3).mode(1 downto 0) 491 | & this'register.st(2).mode(1 downto 0) 492 | & this'register.st(1).mode(1 downto 0) 493 | & this'register.st(0).mode(1 downto 0) & '0' 494 | & to_bit(this'register.st(6).run) 495 | & to_bit(this'register.st(5).run) 496 | & to_bit(this'register.st(4).run) 497 | & to_bit(this'register.st(3).run) 498 | & to_bit(this'register.st(2).run) 499 | & to_bit(this'register.st(1).run) 500 | & to_bit(this'register.st(0).run); 501 | gpsif_o.int_en<= this'register.int_en; 502 | gpsif_o.ra <= this'register.ra; 503 | ra_io.ra <= this'register.ra mod 32; 504 | ra_io.inittm <= this'register.inittm(0); 505 | if(this'register.src = BITL_BUS1) then ra_io.blsp1bit <= '1'; 506 | else ra_io.blsp1bit <= '0'; end if; 507 | if(this'register.src = BITL_BUS2) then ra_io.blsp2bit <= '1'; 508 | else ra_io.blsp2bit <= '0'; end if; 509 | tgt_o.d <= tgt_rd; 510 | tgt_o.ack <= this'register.ack; 511 | dma.req <= this'register.dma_req; 512 | -- for debug on FPGA (from here) 513 | -- Read the same data until actual read request. 514 | if this'register.rd = 7 then dbg_b := this.bndry or this.acm_lst; dbg_i := this.sum.i; dbg_q := this.sum.q; 515 | else dbg_b := false; dbg_i := this.add.i; dbg_q := this.add.q; end if; 516 | dbg_v := (dbg_b or devo.v or reg_i.angle.we = '1' or this'register.rd = 6) and 517 | this'register.dbg_st = DBG_RUN; 518 | if vtoi(itov(this'register.dbg2ms,12) & 519 | itov(this'register.odd_ms, 1) & 520 | to_slv(this'register.cnt1ms)) = this'register.dbg_strt 521 | and this'register.dbg_st = DBG_RDY then this.dbg_st := DBG_RUN; end if; 522 | if dbg_v or dbg_r then if this.dbg_a = 255 then this.dbg_st := DBG_IDL; 523 | this.dbg_a := 0; 524 | else this.dbg_a := this.dbg_a +1; end if; end if; 525 | dbg_a <= itov(this.dbg_a,8); 526 | dbg_w <= to_bit(dbg_v); 527 | dbg_wd(0) <= itov(this'register.ra,8) 528 | & itov(dbg_i,12) 529 | & itov(dbg_q,12); 530 | dbg_wd(1) <= buf_bus.d -- & to_bit(devo.v) & devo.d 531 | & regfile_o.angle(regfile_o.angle'high downto 14) 532 | & to_slv(this'register.cnt1ms) 533 | & itov(this'register.rd,3); 534 | dbg_wd(2) <= reg_i.angle.we & ring_i.stall & ring_o.word.fr & ring_o.word.d 535 | & itov(this'register.dbg2ms,7) & itov(this'register.odd_ms,1) 536 | -- & itov(this.dbg_a,4) 537 | -- & itov(wa,4) 538 | & this'register.st(1).mode(1 downto 0) 539 | & this'register.st(0).mode(1 downto 0) 540 | & to_bit(this'register.st(1).run) 541 | & to_bit(this'register.st(0).run) 542 | & to_bit(dbg_v) & to_bit(dbg_r) 543 | & this'register.ch 544 | & to_bit(wa = 0 and this.nd /= GPSIF_ND_MAX); 545 | -- for debug on FPGA (to here) 546 | regfile_i <= reg_i; 547 | dev_o <= devo; 548 | end process; 549 | end beh; 550 | -------------------------------------------------------------------------------- /gpsif_buf.vhm: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use work.gpsif_pack.all; 4 | 5 | entity gpsif_buf is port ( 6 | clk : in std_logic; 7 | rst : in std_logic; 8 | -- port 9 | gps_clk : in std_logic; 10 | gps_d : in std_logic_vector(1 downto 0); 11 | a : in gpsif_buf_ct_t; 12 | y : out gpsif_buf_i_t; 13 | waf : out gpsif_buf_rw_t ); 14 | end gpsif_buf; 15 | 16 | architecture beh of gpsif_buf is 17 | register variable this : gpsif_buf_reg_t reset := gpsif_buf_reg_RESET; 18 | register variable this_sync : gpsif_buf_sync_t reset := gpsif_buf_sync_RESET; 19 | 20 | begin 21 | pi : process(this,gps_d) 22 | variable wa : integer range 0 to 31; 23 | register this when gps_clk = '1' and gps_clk'event reset sync when rst = '1'; 24 | begin 25 | case this.wa/8 is -- MS 2 bits: 00=>01=>10=>11 26 | when 2 => wa := 24 + (this.wa mod 8); 27 | when 3 => wa := 16 + (this.wa mod 8); 28 | when others => wa := this.wa; 29 | end case; 30 | this.d(wa) := gps_d; 31 | case this.wa is -- MS 2 bits: 00=>01=>11=>10 32 | when 15 => this.wa := 24; 33 | when 31 => this.wa := 16; 34 | when 23 => this.wa := 0; 35 | when others => this.wa := (this.wa + 1) mod 32; 36 | end case; 37 | end process; 38 | 39 | po : process(this_sync,this) 40 | variable wa : integer range 0 to 3; 41 | register this_sync when clk = '1' and clk'event reset sync when rst = '1'; 42 | begin 43 | case this_sync.wa_out is 44 | when 2 => wa := 3; 45 | when 3 => wa := 2; 46 | when others => wa := this_sync.wa_out; 47 | end case; 48 | this_sync.wa_out := this_sync.wa_dly; 49 | this_sync.wa_dly := this'register.wa/8; -- other than lower 3 bits 50 | y.wa <= wa; 51 | end process; 52 | -- connect outputs 53 | y.d <= this'register.d(a.ra); -- data specified by a is stable 54 | waf <= this'register.wa; 55 | end beh; 56 | -------------------------------------------------------------------------------- /gpsif_config_asic.vhd: -------------------------------------------------------------------------------- 1 | configuration gpsif_asic of gpsif is 2 | for beh 3 | for regfile : gpsif_regfile 4 | use entity work.gpsif_regfile(beh); 5 | for beh 6 | for all : bist_RF1 7 | use configuration work.bist_rf1_asic; 8 | end for; 9 | for all : bist_RF2 10 | use configuration work.bist_rf2_asic; 11 | end for; 12 | end for; 13 | end for; 14 | end for; 15 | end configuration; 16 | 17 | configuration gpsif_top_asic of gpsif_top is 18 | for arch 19 | for g : gpsif 20 | use configuration work.gpsif_asic; 21 | end for; 22 | end for; 23 | end configuration; 24 | -------------------------------------------------------------------------------- /gpsif_config_fpga.vhd: -------------------------------------------------------------------------------- 1 | configuration gpsif_fpga of gpsif is 2 | for beh 3 | for regfile : gpsif_regfile 4 | use entity work.gpsif_regfile(beh); 5 | for beh 6 | for all : bist_RF1 7 | use configuration work.bist_rf1_inferred; 8 | end for; 9 | for all : bist_RF2 10 | use configuration work.bist_rf2_inferred; 11 | end for; 12 | end for; 13 | end for; 14 | end for; 15 | end configuration; 16 | 17 | configuration gpsif_top_fpga of gpsif_top is 18 | for arch 19 | for g : gpsif 20 | use configuration work.gpsif_fpga; 21 | end for; 22 | end for; 23 | end configuration; 24 | -------------------------------------------------------------------------------- /gpsif_config_sim.vhd: -------------------------------------------------------------------------------- 1 | configuration gpsif_sim of gpsif is 2 | for beh 3 | for all : ram_1rw 4 | use entity work.ram_1rw(inferred); 5 | end for; 6 | for regfile : gpsif_regfile 7 | use entity work.gpsif_regfile(beh); 8 | for beh 9 | for all : bist_RF1 10 | use configuration work.bist_rf1_inferred; 11 | end for; 12 | end for; 13 | end for; 14 | end for; 15 | end configuration; 16 | 17 | configuration gpsif_top_sim of gpsif_top is 18 | for arch 19 | for g : gpsif 20 | use configuration work.gpsif_sim; 21 | end for; 22 | end for; 23 | end configuration; 24 | -------------------------------------------------------------------------------- /gpsif_db.vhm: -------------------------------------------------------------------------------- 1 | -- The gpsif_db connects the gpsif to the CPU data bus. 2 | -- 3 | library ieee; 4 | use ieee.std_logic_1164.all; 5 | use ieee.numeric_std.all; 6 | 7 | use work.gpsif_pack.all; 8 | use work.cpu2j0_pack.all; 9 | use work.rf_pack.all; 10 | use work.bist_pack.all; 11 | 12 | entity gpsif_db is port ( 13 | clk : in std_logic; 14 | rst : in std_logic; 15 | bi : in bist_scan_t; 16 | bo : out bist_scan_t; 17 | db_i : in cpu_data_o_t; 18 | db_o : out cpu_data_i_t; 19 | tgt_o : in cpu_data_i_t; 20 | tgt_i : out gpsif_tgt_i_t; 21 | time_i : in gpsif_time_t; 22 | intrpt : out std_logic; 23 | a : in gpsif_o_t; 24 | y : out gpsif_i_t); 25 | end entity; 26 | 27 | architecture beh of gpsif_db is 28 | type state_t is ( 29 | FILL, -- Let CPU write gps data 30 | BUSY -- Wait for gpsif input buffer available 31 | ); 32 | constant BUF_ADDR_WIDTH : integer := 4; 33 | subtype buf_ptr_t is integer range 0 to 2**BUF_ADDR_WIDTH-1; 34 | 35 | type gpsif_db_reg_t is record 36 | state : state_t; 37 | ms : std_logic_vector(1 downto 0); 38 | tm : std_logic_vector(1 downto 0); 39 | int : gpsif_int_t; -- interrupt status 40 | intrpt : std_logic; -- interrupt occurs 41 | err : std_logic; 42 | wa : buf_ptr_t; 43 | ack : std_logic; 44 | tgt_i : gpsif_tgt_reg_t; 45 | end record; 46 | constant GPSIF_DB_RESET : gpsif_db_reg_t := ( state => FILL, wa => 0, intrpt => '0', err => '0', ack => '0', 47 | tgt_i => ('0', others => (others => '0')), 48 | others => (others => '0')); 49 | register variable this : gpsif_db_reg_t reset := GPSIF_DB_RESET; 50 | 51 | type mem_loc_t is (GPSIF_REG, INPUT_BUF, GPSTM_REG, NONE ); 52 | signal mem_loc : mem_loc_t := NONE; 53 | signal buf_db_o : cpu_data_i_t; 54 | signal gps_db_o : cpu_data_i_t; 55 | signal tim_db_o : cpu_data_i_t; 56 | signal buf_we : std_logic; 57 | signal buf_re : std_logic; 58 | signal tim_re : std_logic; 59 | signal buf_ra : buf_ptr_t; 60 | signal buf_rd : std_logic_vector(31 downto 0); 61 | 62 | -- memory map: 63 | -- 0x000 - 018 shift to ajust C/A code 64 | -- 0x020 - 038 g2 init. of C/A code 65 | -- 0x040 - 058 PNCO 66 | -- 0x060 GPSIF control (write only) reset, INT, debug 67 | -- 0x080 - 088 Dump signals for Debug 68 | -- 0x100 - 1d4 ch0-6,E/P/L,I/Q -- 7*3*2 registers 69 | -- 0x200 - 204 GPSIF status (read only) 70 | -- 0x200 - 204 input sink 71 | -- 0x210 - 214 gps time register 72 | 73 | function decode_addr(a : std_logic_vector( 9 downto 2)) 74 | return mem_loc_t is 75 | begin 76 | -- IF_REG = for debug enlarging : {0x000 - 0x1fc, 0x300 - 0x3fc} 77 | ------ 78 | if (a(9) = '0') or 79 | (a(8) = '1') then return GPSIF_REG; 80 | else case a(8 downto 3) is 81 | when "000000" => return INPUT_BUF; 82 | when "000010" => return GPSTM_REG; 83 | when others => return NONE; 84 | end case; end if; 85 | end function; 86 | 87 | begin 88 | -------- handle CPU data bus -------- 89 | mem_loc <= decode_addr(this'register.tgt_i.a); 90 | 91 | -- select appropriate outgoing data bus 92 | with mem_loc select 93 | db_o <= 94 | gps_db_o when GPSIF_REG, 95 | buf_db_o when INPUT_BUF, 96 | tim_db_o when GPSTM_REG, 97 | ((others => '0'), '0') when others; 98 | 99 | -- connect gpsif bus 100 | tgt_i <= ( this'register.ack and to_bit(mem_loc = GPSIF_REG), 101 | this'register.tgt_i.wr, this'register.tgt_i.a, this'register.tgt_i.d); 102 | gps_db_o <= (tgt_o.d,this'register.ack); 103 | 104 | -------- Input Buffer connected to CPU bus -------- 105 | -- STATUS register (Read only) 106 | buf_db_o <= (this'register.ms & a.sr 107 | & this'register.tm 108 | & this'register.int 109 | & this'register.err & to_bit(this'register.state = FILL), 110 | this'register.ack); 111 | buf_we <= this'register.ack and this'register.tgt_i.wr and to_bit(mem_loc = INPUT_BUF and this'register.state = FILL); 112 | buf_re <= this'register.ack and not this'register.tgt_i.wr and to_bit(mem_loc = INPUT_BUF); 113 | tim_re <= this'register.ack and not this'register.tgt_i.wr and to_bit(mem_loc = GPSTM_REG); 114 | buf_ra <= a.ra/16; 115 | 116 | tim_db_o <= (time_i.seq & std_logic_vector(time_i.nsec), 117 | this'register.ack); 118 | intrpt <= this'register.intrpt; 119 | 120 | -- Instantiate register file for input buffer and connect buffer bus to it. 121 | -- Input tbl 256 pairs of sign/mag bits = 16*32 122 | -- Use a 1R/1W register file. 123 | r : bist_RF1 124 | generic map ( WIDTH => 32, DEPTH => 2**BUF_ADDR_WIDTH ) 125 | port map 126 | (clk => clk, 127 | rst => rst, 128 | bi => bi, 129 | bo => bo, 130 | D => db_i.d, 131 | WA => this'register.wa, 132 | WE => buf_we, 133 | RA0 => buf_ra, 134 | Q0 => buf_rd); 135 | 136 | p : process(this, a, db_i, tgt_o, buf_we, buf_re, tim_re, time_i) 137 | register this when clk = '1' and clk'event reset sync when rst = '1'; 138 | variable int : gpsif_int_t; 139 | begin 140 | this.ack := db_i.en and not this'register.ack; 141 | this.tgt_i := (db_i.wr, db_i.a(9 downto 2), db_i.d); 142 | 143 | if buf_we = '1' then this.wa := (this.wa + 1) mod 16; end if; 144 | if this.wa = 0 and not a.cntl.lst then this.state := BUSY; 145 | else this.state := FILL; end if; 146 | -- Check if read is too late, set err, and clear status 147 | if a.cntl.err then this.err := '1'; end if; -- VLD (accumulate err) 148 | if tim_re = '1' then if this.tm(1 downto 0) = "11" then this.err := '1'; end if; -- Time (accumulate err) 149 | this.tm(1 downto 0):= "00"; end if; -- Clear after time read 150 | if buf_re = '1' then this.err := this.ms(1) and this.ms(0); -- Clear old err after status read, and set new err. 151 | this.ms(1 downto 0):= "00"; -- Clear after status read 152 | this.int := (others => '0'); end if; -- clear after status read 153 | -- Uptate status, check interrupt condition, and assert intrpt 154 | int := a.cntl.ovr & "00" & a.cntl.vld; 155 | if time_i.setnsec = '1' then 156 | if time_i.mscnt = '1' then this.tm(1) := '1'; int(2) := '1'; int(3) := int(3) or this.tm(0); -- 1 pps is in odd region 157 | else this.tm(0) := '1'; int(2) := '1'; int(3) := int(3) or this.tm(1); end if; end if; -- 1 pps is in even region 158 | if a.cntl.bndry then if a.odd then this.ms(1) := '1'; int(1) := '1'; int(3) := int(3) or this.ms(0); -- in odd region now 159 | else this.ms(0) := '1'; int(1) := '1'; int(3) := int(3) or this.ms(1); end if; end if; -- in even region now 160 | 161 | this.int := this.int or int; -- accumulte interrupt condition until read 162 | this.intrpt := to_bit((a.int_en and int) /= X"0"); 163 | -- SW reset 164 | if a.rst then this := GPSIF_DB_RESET; end if; 165 | end process; 166 | 167 | -- Returns two neighbouring bits from a vector of 32 bits. 168 | -- The bits are addressed left to right. 169 | -- Address 0 = data(31 downto 30) and address 15 = data(1 downto 0) 170 | y.d <= buf_rd(31 - 2*(a.ra mod 16) downto 30 - 2*(a.ra mod 16)); 171 | y.wa <= this'register.wa *2; 172 | 173 | end beh; 174 | -------------------------------------------------------------------------------- /gpsif_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.std_logic_unsigned.all; 4 | use ieee.numeric_std.all; 5 | 6 | use work.fixed_pkg.all; 7 | use work.rf_pack.all; 8 | use work.bist_pack.all; 9 | use work.cpu2j0_pack.all; 10 | use work.ring_bus_pack.all; 11 | use work.rbus_pack.all; 12 | use work.gpsif_sub_pack.all; 13 | 14 | -- Code Freq.(Fco): 1.023 MHz, 1023 / 1.023MHz = 1 ms 15 | -- Carrier Freq.(Fc ): 1540*Fco = 1575.42 MHz (used by analog part) 16 | -- 1st Local Freq.(Fl ): 96*16*Fco = 1571.328 MHz (used by analog part) 17 | -- Sampling Freq.(Fs ): 16*Fco = 16.368 MHz, dt = 1/Fs, 16,368 samples/ms 18 | -- Intermediate Freq.(IF ): 4*Fco = 4.092 MHz, Fc - Fl 19 | 20 | -- Doppler Shift: Max +-10kHz/s, +-200Hz/20ms 21 | 22 | package gpsif_pack is 23 | 24 | constant GPSIF_TARGET_BUS_WIDTH : natural := 32; 25 | 26 | constant GPSIF_NC_BITS : natural := 3; 27 | constant GPSIF_NC_MAX : natural := 6; 28 | constant GPSIF_ND_MAX : natural := 31; 29 | constant GPSIF_RD_MAX : natural := 7; -- fixed to 7 now 30 | constant GPSIF_RW_MAX : natural := (GPSIF_ND_MAX+1)*(GPSIF_RD_MAX+1)-1; 31 | constant GPSIF_WA_MAX : natural := (GPSIF_RW_MAX+1)/8-1; 32 | constant GPSIF_CA_BITS : natural := 10; 33 | constant GPSIF_SFT_RNG : natural := 2**(GPSIF_CA_BITS+4); 34 | 35 | function itov(X, N : integer) return std_logic_vector; 36 | function vtoi(X : std_logic_vector) return integer; 37 | function vtoui(X : std_logic_vector) return integer; 38 | function to_bit(b : boolean) return std_logic; 39 | 40 | --- sincos ------------------------------------------------------------------- 41 | constant GPSIF_ANGLE_BITS : natural :=30; -- More than 1 rotation can be discarded. 42 | constant GPSIF_ANGLE_INDX : natural := 6; -- scaled by 2**ANGLE_INDX/2PI (PI=>32, range is 0 to 63) 43 | constant GPSIF_SINCOS_MAX : natural := 5; -- scaled by 2**(SINCOSBITS-1) ( 1=>32, range is 0 to 32) 44 | constant GPSIF_CRRMIX_MAX : natural := GPSIF_SINCOS_MAX+ 2; -- (-32*3 to 32*3) to signed here 45 | constant GPSIF_SUMREG_MAX : natural := GPSIF_CRRMIX_MAX+ 3; -- (-32*3*8 to 32*3*8) 46 | constant GPSIF_ACMREG_MAX : natural := GPSIF_SUMREG_MAX+11; -- 1ms*16*1023samples 47 | 48 | subtype gpsif_angle_reg_t is std_logic_vector(GPSIF_ANGLE_BITS-1 downto 0); 49 | subtype gpsif_angle_t is ufixed(GPSIF_ANGLE_BITS-1 downto 0); 50 | subtype gpsif_angle_a_t is integer range 0 to GPSIF_NC_MAX; 51 | subtype gpsif_carrmix_t is integer range -(2**GPSIF_CRRMIX_MAX) to 2**GPSIF_CRRMIX_MAX; -- -96 to 96 52 | 53 | type gpsif_carrmix_o_t is record 54 | i,q : gpsif_carrmix_t; -- -96 to 96 (32*3 = 96, X"A0" to X"60") 55 | end record; 56 | 57 | type gpsif_carrmix_i_t is record 58 | angle : ufixed(GPSIF_ANGLE_INDX-1 downto 0); 59 | d : std_logic_vector( 1 downto 0); -- 00: 1, 01: 3, 10:-1, 11:-3 60 | end record; 61 | 62 | function gpsif_carrmix(a : gpsif_carrmix_i_t) return gpsif_carrmix_o_t; 63 | function gpsif_sin_6b (a : ufixed(3 downto 0)) return ufixed; 64 | function gpsif_mul (a : ufixed(1 downto 0); b : std_logic_vector(1 downto 0); 65 | s,c : ufixed(GPSIF_SINCOS_MAX downto 0)) return gpsif_carrmix_t; 66 | 67 | --- sumreg -------------------------------------------------------------------- 68 | subtype gpsif_sum_d_t is integer range -(2**GPSIF_SUMREG_MAX) to 2**GPSIF_SUMREG_MAX; -- -768 to 768 (X"500" to X"300") 69 | 70 | type gpsif_sum_t is record 71 | i,q : gpsif_sum_d_t; 72 | end record; 73 | 74 | --- C/A code ------------------------------------------------------------------- 75 | subtype gpsif_sftca_reg_t is std_logic_vector(GPSIF_CA_BITS*2-1 downto 0); 76 | subtype gpsif_sftca_a_t is integer range 0 to GPSIF_NC_MAX * 2 + 1; 77 | subtype gpsif_sft_t is ufixed(GPSIF_CA_BITS+3 downto 0); 78 | subtype gpsif_cnt1ms_t is ufixed(GPSIF_CA_BITS downto 0); 79 | 80 | --- acmreg -------------------------------------------------------------------- 81 | constant GPSIF_REG_PER_CH : natural := 6; 82 | constant GPSIF_ACMREG_NUM : natural := (GPSIF_NC_MAX+1)*GPSIF_REG_PER_CH; 83 | 84 | subtype gpsif_acm_a_t is integer range 0 to GPSIF_ACMREG_NUM/2 -1; 85 | subtype gpsif_acm_d_t is integer range -(2**GPSIF_ACMREG_MAX) to 2**GPSIF_ACMREG_MAX-1; 86 | subtype gpsif_acm_reg_t is std_logic_vector (GPSIF_ACMREG_MAX downto 0); 87 | 88 | --- regfile -------------------------------------------------------------------- 89 | type gpsif_regin_angle_t is record 90 | wd : gpsif_angle_reg_t; 91 | we : std_logic; 92 | a : gpsif_angle_a_t; 93 | end record; 94 | 95 | type gpsif_regin_sftca_t is record 96 | wd : gpsif_sftca_reg_t; 97 | we : std_logic; 98 | wa : gpsif_sftca_a_t; 99 | ra : gpsif_sftca_a_t; 100 | end record; 101 | 102 | type gpsif_regin_acm_t is record 103 | a : gpsif_acm_a_t; 104 | wd : gpsif_acm_reg_t; 105 | we : std_logic; 106 | bs : std_logic; 107 | end record; 108 | 109 | type gpsif_regfile_i_t is record 110 | pnco : gpsif_regin_angle_t; 111 | angle : gpsif_regin_angle_t; 112 | sftca : gpsif_regin_sftca_t; 113 | sftca_obs : gpsif_regin_sftca_t; 114 | acm : gpsif_regin_acm_t; 115 | buf : gpsif_regin_acm_t; 116 | end record; 117 | 118 | type gpsif_regfile_o_t is record 119 | pnco : gpsif_angle_reg_t; 120 | angle : gpsif_angle_reg_t; 121 | sftca : gpsif_sftca_reg_t; 122 | sftca_obsv : gpsif_sftca_reg_t; 123 | acm : gpsif_acm_reg_t; 124 | buf : gpsif_acm_reg_t; 125 | end record; 126 | 127 | component gpsif_regfile is port ( 128 | clk : in std_logic; 129 | rst : in std_logic; 130 | bi : in bist_scan_t; 131 | bo : out bist_scan_t; 132 | a : in gpsif_regfile_i_t; 133 | y : out gpsif_regfile_o_t); 134 | end component; 135 | 136 | --- gpsif -------------------------------------------------------------------- 137 | subtype gpsif_rw_t is integer range 0 to GPSIF_RW_MAX; 138 | subtype gpsif_wa_t is integer range 0 to GPSIF_WA_MAX; 139 | 140 | subtype gpsif_buf_rw_t is integer range 0 to 31; 141 | subtype gpsif_buf_wa_t is integer range 0 to 3; 142 | subtype gpsif_int_t is std_logic_vector(3 downto 0); 143 | 144 | type gpsif_cntl_t is record 145 | vld : std_logic; 146 | ovr : std_logic; 147 | bndry : boolean; 148 | err : boolean; 149 | lst : boolean; 150 | end record; 151 | type gpsif_o_t is record 152 | ra : gpsif_rw_t; 153 | sr : std_logic_vector(21 downto 0); 154 | cntl : gpsif_cntl_t; 155 | odd : boolean; 156 | rst : boolean; 157 | int_en : gpsif_int_t; 158 | end record; 159 | 160 | type gpsif_buf_ct_t is record 161 | ra : gpsif_buf_rw_t; 162 | inittm : std_logic; 163 | blsp1bit : std_logic; 164 | blsp2bit : std_logic; 165 | end record; 166 | type gpsif_time_t is record 167 | seq : std_logic_vector(7 downto 0); 168 | nsec : unsigned(23 downto 0); 169 | setnsec : std_logic; 170 | mscnt : std_logic; 171 | d : std_logic_vector(1 downto 0); 172 | wa : gpsif_wa_t; 173 | end record; 174 | 175 | -- sft & pnco update command format 176 | -- 31 : write dma channel & sft value 177 | -- 30-29 : sft value update type ( NOP, INC, PLS, MNS ) 178 | -- 28 : pnco value inc. or not 179 | -- 27 : sft inc. code set or not 180 | -- 26-24 : sft inc. code (not a value itself) 181 | -- 23 : pnco inc. code set or not 182 | -- 22-20 : pnco inc. code (not a value itself) 183 | -- 19-14 : dma channel 184 | -- 13- 0 : sft 185 | 186 | subtype gpsif_sft_fld_t is std_logic_vector(30 downto 29); 187 | subtype gpsif_sft_inc_t is std_logic_vector(26 downto 24); 188 | subtype gpsif_pncoinc_t is std_logic_vector(22 downto 20); 189 | 190 | type gpsif_src_t is ( IO_PIN, CPU_BUS, BITL_BUS1, BITL_BUS2 ); 191 | type gpsif_sft_typ_t is ( NOP, pad, SKP, AGN ); 192 | type gpsif_sft_chg_t is ( NOP, INC, PLS, MNS ); 193 | -- Channel mode encoding 194 | -- (2): TRK or not 195 | -- (1): VLD ODD, IDL or ACQ 196 | -- (0): VLD EVN 197 | -- 00-: IDL, 01-: ACQ, 100: TRK & not VLD, 101: TRK & VLD EVN, 110: TRK & VLD ODD, 111: TRK & VLD both (fail to read) 198 | type gpsif_st_t is record 199 | mode : std_logic_vector(2 downto 0); 200 | run : boolean; 201 | pnco : boolean; -- pnco increment by this.inc 202 | sft : gpsif_sft_chg_t; 203 | end record; 204 | type gpsif_sft_st_t is record 205 | chg : gpsif_sft_chg_t; 206 | typ : gpsif_sft_typ_t; 207 | ext : boolean; 208 | end record; 209 | type gpsif_ch_st_t is array (0 to GPSIF_NC_MAX) of gpsif_st_t; 210 | type gpsif_inc_t is record 211 | sft : std_logic_vector(2 downto 0); 212 | pnco : std_logic_vector(2 downto 0); 213 | end record; 214 | subtype gpsif_ch_t is std_logic_vector(GPSIF_NC_BITS-1 downto 0); 215 | constant GPSIF_NC_END : gpsif_ch_t := (others => '0'); 216 | constant DBG_2MS_MAX : natural := 2**12 -1; 217 | subtype gpsif_dbg2ms_t is integer range 0 to DBG_2MS_MAX; 218 | type gpsif_dbg_st_t is ( DBG_IDL, DBG_RDY, DBG_RUN ); 219 | 220 | type gpsif_reg_t is record 221 | -- config 222 | src : gpsif_src_t; 223 | src_bls : std_logic; -- 0:2bits/spl 1:1bit/spl 224 | inc : gpsif_inc_t; 225 | int_en : gpsif_int_t; 226 | -- state 227 | sft : gpsif_sft_st_t; 228 | st : gpsif_ch_st_t; 229 | -- delayed info. 230 | ready : boolean; -- input data is ready (scope data is stable) 231 | bndry : boolean; -- at 1ms boundary of carier mix channel 232 | even : boolean; -- 1st half of 16 cycles 233 | acm_lst : boolean; -- at 1ms boundary of accumulating channel 234 | acm_en : boolean; -- enable accumulation 235 | scp_chg : boolean; -- ND scope is changed by SHIFT change 236 | rst_en : boolean; -- SW reset enable 237 | -- counters 238 | ch : gpsif_ch_t; 239 | rd : integer range 0 to GPSIF_RD_MAX; 240 | nd : integer range 0 to GPSIF_ND_MAX; 241 | cnt1ms : gpsif_cnt1ms_t; 242 | odd_ms : integer range 0 to 1; -- even/odd ms 243 | -- latched values 244 | sum : gpsif_sum_t; 245 | add : gpsif_sum_t; 246 | code : std_logic_vector(2 downto 0); 247 | -- output 248 | dma_req : std_logic_vector(DMA_CH_NUM_LOG downto 0); 249 | ack : std_logic; 250 | ra : gpsif_rw_t; 251 | inittm : std_logic_vector(1 downto 0); 252 | -- for debug 253 | dbg_st : gpsif_dbg_st_t; 254 | dbg_strt : integer range 0 to 2**24 -1; 255 | dbg_a : integer range 0 to 255; 256 | dbg2ms : gpsif_dbg2ms_t; 257 | end record; 258 | 259 | constant GPSIF_REG_RESET : gpsif_reg_t := ( 260 | src => IO_PIN, src_bls => '0', 261 | inc => (others => (others => '0')), int_en => (others => '0'), 262 | st => (others => (mode => (others => '0'), sft => NOP, pnco => false, run => false)), 263 | sft => (chg => NOP, typ => NOP, ext => false), 264 | ready => false, bndry => false, even => false, acm_lst => false, acm_en => false, 265 | scp_chg => false, rst_en => false, 266 | ch => GPSIF_NC_END, 267 | rd => GPSIF_RD_MAX, 268 | nd => GPSIF_ND_MAX, 269 | cnt1ms => (1 => '0', others => '1'), -- 2045 = 7fd 270 | odd_ms => 1, -- start from all 1 271 | sum => (others => 0), 272 | add => (others => 0), 273 | code => (others => '0'), 274 | dma_req => (others => '0'), 275 | ack => '0', 276 | ra => GPSIF_RW_MAX, 277 | inittm => (others => '0'), 278 | dbg_st => DBG_IDL, dbg_strt => 0, dbg_a => 0, dbg2ms => DBG_2MS_MAX ); 279 | 280 | type gpsif_i_t is record 281 | d : std_logic_vector(1 downto 0); 282 | wa : gpsif_wa_t; 283 | end record; 284 | type gpsif_tgt_i_t is record 285 | en,wr: std_logic; 286 | a : std_logic_vector( 9 downto 2); 287 | d : std_logic_vector(31 downto 0); 288 | end record; 289 | type gpsif_tgt_reg_t is record -- for slower bus_clk than clk 290 | wr: std_logic; 291 | a : std_logic_vector( 9 downto 2); 292 | d : std_logic_vector(31 downto 0); 293 | end record; 294 | type gpsif_buf_i_t is record 295 | d : std_logic_vector(1 downto 0); 296 | wa : gpsif_buf_wa_t; 297 | end record; 298 | 299 | type gpsif_buf_t is array (0 to 31) of std_logic_vector(1 downto 0); 300 | 301 | type gpsif_time_rt_t is record 302 | nsec : unsigned (23 downto 0); 303 | nsec_cap : unsigned (23 downto 0); 304 | round_s : integer range 0 to 20; 305 | round_l : integer range 0 to 2386; 306 | pps_dly : std_logic_vector (3 downto 0); 307 | inittm : std_logic; 308 | cnt1ms_g : gpsif_cnt1ms_t; 309 | cnt1msup_g : std_logic; 310 | end record; 311 | type gpsif_buf_reg_t is record 312 | d : gpsif_buf_t; 313 | wa : gpsif_buf_rw_t; 314 | end record; 315 | type gpsif_time_reg_t is record 316 | rt : gpsif_time_rt_t; 317 | end record; 318 | type gpsif_buf_sync_t is record 319 | wa_dly : gpsif_buf_wa_t; 320 | wa_out : gpsif_buf_wa_t; 321 | end record; 322 | type gpsif_time_sync_t is record 323 | ppss_dly : std_logic_vector (2 downto 0); 324 | nsec : unsigned (23 downto 0); 325 | cnt1msup_g : std_logic; 326 | setnsec : std_logic; 327 | packetwd : std_logic_vector (15 downto 0); 328 | packetwa : integer range 0 to 31; 329 | packetwe : std_logic; 330 | wa_comm : integer range 0 to 64; -- 2bit sample max 32, 1 bit sample max 64 331 | wa_commwait : integer range 0 to 63; 332 | inittmc1 : std_logic_vector(1 downto 0); 333 | inittmc2 : integer range 0 to 64; 334 | inittmc3 : std_logic; 335 | pon_state : std_logic; 336 | rt : gpsif_time_rt_t; 337 | end record; 338 | 339 | constant gpsif_time_rt_RESET : gpsif_time_rt_t := (nsec => (others => '0'), 340 | nsec_cap => (others => '0'), round_s => 0, round_l => 0, pps_dly => "0000", 341 | inittm => '0', cnt1ms_g => (others => '0'), cnt1msup_g => '0' ); 342 | constant gpsif_buf_reg_RESET : gpsif_buf_reg_t := (d => (others => (others => '0')), wa => 0 ); 343 | constant gpsif_buf_sync_RESET : gpsif_buf_sync_t := (wa_dly => 0, wa_out => 0); 344 | constant gpsif_time_reg_RESET : gpsif_time_reg_t := (rt => gpsif_time_rt_RESET ); 345 | constant gpsif_time_sync_RESET : gpsif_time_sync_t := (ppss_dly => "000", 346 | nsec => (others => '0'), cnt1msup_g => '0', setnsec => '0', 347 | packetwd => x"0000", packetwa => 31, packetwe => '1', 348 | wa_comm => 64, wa_commwait => 0 , 349 | inittmc1 => "00", inittmc2 => 0, inittmc3 => '0', pon_state => '1', 350 | rt => gpsif_time_rt_RESET ); 351 | 352 | component gpsif_buf is port ( 353 | clk : in std_logic; 354 | rst : in std_logic; 355 | -- port 356 | gps_clk : in std_logic; 357 | gps_d : in std_logic_vector(1 downto 0); 358 | a : in gpsif_buf_ct_t; 359 | y : out gpsif_buf_i_t; 360 | waf : out gpsif_buf_rw_t ); 361 | end component; 362 | 363 | component gpsif_time is port ( 364 | clk : in std_logic; 365 | rst : in std_logic; 366 | -- port 367 | gps_clk : in std_logic; 368 | gps_d : in std_logic_vector(1 downto 0); 369 | a : in gpsif_buf_ct_t; 370 | waf : in gpsif_buf_rw_t; 371 | ppsdds : in std_logic; 372 | blgps : in blgps_t; 373 | y : out gpsif_time_t ); 374 | end component; 375 | 376 | component gpsif is 377 | generic ( GPSIF_NC : integer := 7; 378 | ANGLE_INI_OLD : boolean := false ); 379 | port ( 380 | clk : in std_logic; 381 | rst : in std_logic; 382 | bi : in bist_scan_t; 383 | bo : out bist_scan_t; 384 | ring_i : in rbus_9b; -- to monitor ring bus 385 | ring_o : in rbus_9b; -- to monitor ring bus 386 | tgt_o : out cpu_data_i_t; 387 | tgt_i : in gpsif_tgt_i_t; 388 | dev_o : out rbus_dev_o_t; 389 | dev_i : in rbus_dev_i_t; 390 | buf_io : in gpsif_buf_i_t; 391 | time_i : in gpsif_time_t; 392 | ra_io : out gpsif_buf_ct_t; 393 | buf_bus : in gpsif_i_t; 394 | gpsif_o : out gpsif_o_t; 395 | dma : out dma_req_t ); 396 | end component; 397 | 398 | component gpsif_db is port ( 399 | clk : in std_logic; 400 | rst : in std_logic; 401 | bi : in bist_scan_t; 402 | bo : out bist_scan_t; 403 | db_i : in cpu_data_o_t; 404 | db_o : out cpu_data_i_t; 405 | tgt_o : in cpu_data_i_t; 406 | tgt_i : out gpsif_tgt_i_t; 407 | time_i : in gpsif_time_t; 408 | intrpt : out std_logic; 409 | a : in gpsif_o_t; 410 | y : out gpsif_i_t); 411 | end component; 412 | 413 | end package; 414 | 415 | package body gpsif_pack is 416 | 417 | function itov(X, N : integer) return std_logic_vector is 418 | begin 419 | return std_logic_vector(to_signed(X,N)); 420 | end itov; 421 | 422 | function vtoi(X : std_logic_vector) return integer is 423 | variable v : std_logic_vector(X'high - X'low downto 0) := X; 424 | begin 425 | return to_integer(signed(v)); 426 | end vtoi; 427 | 428 | function vtoui(X : std_logic_vector) return integer is 429 | variable v : std_logic_vector(X'high - X'low downto 0) := X; 430 | begin 431 | return to_integer(unsigned(v)); 432 | end vtoui; 433 | function to_bit(b : boolean) return std_logic is 434 | begin 435 | if b then return '1'; 436 | else return '0'; end if; 437 | end to_bit; 438 | 439 | function gpsif_carrmix(a : gpsif_carrmix_i_t) return gpsif_carrmix_o_t is 440 | alias a_q : ufixed(1 downto 0) is a.angle(a.angle'high downto a.angle'high-1); 441 | variable ca_q : ufixed(2 downto 0); 442 | alias a_1 : ufixed(a.angle'high-2 downto 0) is a.angle(a.angle'high-2 downto 0); -- 1st quadrant angle 443 | variable ca_1 : ufixed(a.angle'high downto 0); 444 | variable y : gpsif_carrmix_o_t; 445 | variable s, c : ufixed(GPSIF_SINCOS_MAX downto 0); 446 | begin 447 | ca_q := 1 + a_q; 448 | ca_1 := "00" & a_1; 449 | ca_1 := 2**a_1'length - ca_1(a_1'length downto 0); 450 | 451 | s := gpsif_sin_6b( a_1); -- sin of 1st quadrant 452 | c := gpsif_sin_6b(ca_1(a_1'range)); -- cos(a_1) = sin(scaled(PI/2) - a_1) = sin(ca_1) 453 | if ca_1(ca_1'high-1)='1' then c := "100000"; -- to make cos(0) := 32 454 | end if; 455 | y.i := gpsif_mul( a_q, a.d, s, c); -- c is sin of 2nd quadrant 456 | y.q := gpsif_mul(ca_q(a_q'range), a.d, s, c); 457 | return y; 458 | end gpsif_carrmix; 459 | 460 | function gpsif_sin_6b(a : ufixed(3 downto 0)) return ufixed is 461 | 462 | -- special to 6b output & 4b angle of 1st quadrant 463 | -- angle : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 464 | -- sin : 0 3 6 9 12 15 18 21 23 25 27 29 30 31 32 32 465 | -- cos : 0 32 32 31 30 29 27 25 23 21 18 15 12 9 6 3 : sin(16 - angle), cos(0) must be corrected to 32 after the function. 466 | 467 | variable x1,x2 : ufixed(4 downto 0); 468 | variable y : ufixed(5 downto 0); 469 | begin 470 | if a(3)='0' then x1 := a & '0'; x2 := "0" & a; -- 2x + x = 3x 471 | elsif a(2)='0' then x1 := a & '0'; x2 := "00111"; -- 2x + 7 472 | elsif a(1)='0' then x1 := "10010"; x2 := "0" & a; -- 18 + x 473 | else x1 := "10010"; x2 := "01110"; -- 18 +14 = 32 474 | end if; 475 | y := x1 + x2; 476 | return y; 477 | end gpsif_sin_6b; 478 | 479 | 480 | function gpsif_mul(a : ufixed(1 downto 0); b : std_logic_vector(1 downto 0); 481 | s, c : ufixed(GPSIF_SINCOS_MAX downto 0)) return gpsif_carrmix_t is 482 | 483 | -- quadrant I II III IV 484 | -- sin s c -s -c : s is sin of 1st quadrant 485 | -- cos c -s -c s : c is cos of 1st quadrant 486 | 487 | variable sc,sc4,y : ufixed(GPSIF_CRRMIX_MAX downto 0); 488 | variable ci,dummy : std_logic; 489 | begin 490 | ci := '1'; -- for other than *(+1) case 491 | case a(0) is 492 | when '0' => sc := ("00" & s); sc4 := (s & "00"); -- 1st, 3rd quadrant 493 | when '1' => sc := ("00" & c); sc4 := (c & "00"); -- 2nd, 4th quadrant 494 | when others => 495 | end case; 496 | case (a(1) xor b(1)) is 497 | when '0' => -- same sign 498 | case b(0) is 499 | when '0' => ci := '0'; sc4 := (others => '0'); -- *(+1) 500 | when '1' => sc := not sc; -- *(+3) ( 3 = 4 - 1) 501 | when others => 502 | end case; 503 | when '1' => -- different sign 504 | case b(0) is 505 | when '0' => sc := not sc; sc4 := (others => '0'); -- *(-1) 506 | when '1' => sc4 := not sc4; -- *(-3) (-3 = -4 + 1) 507 | when others => 508 | end case; 509 | when others => 510 | end case; 511 | add_carry(sc, sc4, ci, y, dummy); 512 | return vtoi(to_slv(y)); 513 | end gpsif_mul; 514 | 515 | end gpsif_pack; 516 | -------------------------------------------------------------------------------- /gpsif_reg.vhm: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use work.rf_pack.all; 4 | use work.bist_pack.all; 5 | use work.gpsif_pack.all; 6 | 7 | entity gpsif_regfile is port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | bi : in bist_scan_t; 11 | bo : out bist_scan_t; 12 | a : in gpsif_regfile_i_t; 13 | y : out gpsif_regfile_o_t); 14 | end gpsif_regfile; 15 | 16 | architecture beh of gpsif_regfile is 17 | 18 | signal acm_d0 : gpsif_acm_reg_t; 19 | signal acm_d1 : gpsif_acm_reg_t; 20 | signal we0a : std_logic; 21 | signal we1a : std_logic; 22 | signal bs0 : bist_scan_t; 23 | signal bs1 : bist_scan_t; 24 | signal bs2 : bist_scan_t; 25 | signal bs3 : bist_scan_t; 26 | signal bs4 : bist_scan_t; 27 | signal bs5 : bist_scan_t; 28 | signal bs6 : bist_scan_t; 29 | signal buf_d0 : gpsif_acm_reg_t; 30 | signal buf_d1 : gpsif_acm_reg_t; 31 | signal we0b : std_logic; 32 | signal we1b : std_logic; 33 | 34 | begin 35 | sftca_bank : bist_RF1 36 | generic map ( WIDTH => GPSIF_CA_BITS * 2, DEPTH => (GPSIF_NC_MAX + 1) * 2 ) 37 | port map 38 | (clk => clk, 39 | rst => rst, 40 | bi => bi, 41 | bo => bs1, 42 | D => a.sftca.wd, 43 | WA => a.sftca.wa, 44 | WE => a.sftca.we, 45 | RA0 => a.sftca.ra, 46 | Q0 => y.sftca); 47 | 48 | -- observe sftca ---------- 49 | sftca_observe : bist_RF1 50 | generic map ( WIDTH => GPSIF_CA_BITS * 2, DEPTH => (GPSIF_NC_MAX + 1) * 2 ) 51 | port map 52 | (clk => clk, 53 | rst => rst, 54 | bi => bi, 55 | bo => open, 56 | D => a.sftca.wd, 57 | WA => a.sftca.wa, 58 | WE => a.sftca.we, 59 | RA0 => a.sftca_obs.ra, 60 | Q0 => y.sftca_obsv); 61 | 62 | pnco_bank : bist_RF1 63 | generic map ( WIDTH => GPSIF_ANGLE_BITS, DEPTH => GPSIF_NC_MAX + 1 ) 64 | port map 65 | (clk => clk, 66 | rst => rst, 67 | bi => bs1, 68 | bo => bs2, 69 | D => a.pnco.wd, 70 | WA => a.pnco.a, 71 | WE => a.pnco.we, 72 | RA0 => a.angle.a, 73 | Q0 => y.pnco); 74 | 75 | angle_bank : bist_RF1 76 | generic map ( WIDTH => GPSIF_ANGLE_BITS, DEPTH => GPSIF_NC_MAX + 1 ) 77 | port map 78 | (clk => clk, 79 | rst => rst, 80 | bi => bs2, 81 | bo => bs3, 82 | D => a.angle.wd, 83 | WA => a.angle.a, 84 | WE => a.angle.we, 85 | RA0 => a.angle.a, 86 | Q0 => y.angle); 87 | 88 | we0a <= a.acm.we when (a.acm.bs = '0') else '0'; 89 | we1a <= a.acm.we when (a.acm.bs = '1') else '0'; 90 | we0b <= a.buf.we and a.acm.we when (a.acm.bs = '0') else '0'; 91 | we1b <= a.buf.we and a.acm.we when (a.acm.bs = '1') else '0'; 92 | 93 | acm_bank0 : bist_RF1 94 | generic map ( WIDTH => GPSIF_ACMREG_MAX+1, DEPTH => GPSIF_ACMREG_NUM/2 ) 95 | port map 96 | (clk => clk, 97 | rst => rst, 98 | bi => bs3, 99 | bo => bs4, 100 | D => a.acm.wd, 101 | WA => a.acm.a, 102 | WE => we0a, 103 | RA0 => a.acm.a, 104 | Q0 => acm_d0); 105 | 106 | acm_bank1 : bist_RF1 107 | generic map ( WIDTH => GPSIF_ACMREG_MAX+1, DEPTH => GPSIF_ACMREG_NUM/2 ) 108 | port map 109 | (clk => clk, 110 | rst => rst, 111 | bi => bs4, 112 | bo => bs5, 113 | D => a.acm.wd, 114 | WA => a.acm.a, 115 | WE => we1a, 116 | RA0 => a.acm.a, 117 | Q0 => acm_d1); 118 | 119 | buf_bank0 : bist_RF1 120 | generic map ( WIDTH => GPSIF_ACMREG_MAX+1, DEPTH => GPSIF_ACMREG_NUM/2 ) 121 | port map 122 | (clk => clk, 123 | rst => rst, 124 | bi => bs5, 125 | bo => bs6, 126 | D => a.buf.wd, 127 | WA => a.acm.a, 128 | WE => we0b, 129 | RA0 => a.buf.a, 130 | Q0 => buf_d0); 131 | 132 | buf_bank1 : bist_RF1 133 | generic map ( WIDTH => GPSIF_ACMREG_MAX+1, DEPTH => GPSIF_ACMREG_NUM/2 ) 134 | port map 135 | (clk => clk, 136 | rst => rst, 137 | bi => bs6, 138 | bo => bo, 139 | D => a.buf.wd, 140 | WA => a.acm.a, 141 | WE => we1b, 142 | RA0 => a.buf.a, 143 | Q0 => buf_d1); 144 | 145 | -- connect outputs 146 | y.acm <= acm_d0 when (a.acm.bs = '0') else 147 | acm_d1 ; 148 | y.buf <= buf_d0 when (a.buf.bs = '0') else 149 | buf_d1 ; 150 | end beh; 151 | -------------------------------------------------------------------------------- /gpsif_sub_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.std_logic_unsigned.all; 4 | use ieee.numeric_std.all; 5 | 6 | use work.fixed_pkg.all; 7 | use work.rf_pack.all; 8 | use work.bist_pack.all; 9 | use work.cpu2j0_pack.all; 10 | use work.ring_bus_pack.all; 11 | use work.rbus_pack.all; 12 | 13 | package gpsif_sub_pack is 14 | 15 | -- Copy from dma_pkg.vhd, and change name to avoid conflict 16 | -- Direct reference by "use work.dma_pack.all;" causes error. 17 | constant DMA_CH_NUM_LOG : natural := 6; 18 | type dma_req_t is record 19 | req : std_logic_vector(DMA_CH_NUM_LOG downto 0); 20 | end record; 21 | 22 | constant NULL_DMA_REQ : dma_req_t := ( req => (others => '0') ); 23 | 24 | type blgps_t is record 25 | en : std_logic; 26 | a : std_logic_vector( 5 downto 0); 27 | d : std_logic_vector( 7 downto 0); 28 | tick : std_logic; 29 | end record; 30 | 31 | constant NULL_BLGPS : blgps_t := ( en => '0', a => (others => '0'), 32 | d => x"00", tick => '0' ); 33 | 34 | end package; 35 | 36 | package body gpsif_sub_pack is 37 | 38 | end gpsif_sub_pack; 39 | -------------------------------------------------------------------------------- /gpsif_time.vhm: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use work.fixed_pkg.all; 4 | use ieee.numeric_std.all; 5 | use work.gpsif_pack.all; 6 | use work.gpsif_sub_pack.all; 7 | use work.rf_pack.all; 8 | use work.bist_pack.all; 9 | 10 | entity gpsif_time is port ( 11 | clk : in std_logic; 12 | rst : in std_logic; 13 | -- port 14 | gps_clk : in std_logic; 15 | gps_d : in std_logic_vector(1 downto 0); 16 | a : in gpsif_buf_ct_t; 17 | waf : in gpsif_buf_rw_t; 18 | blgps : in blgps_t; 19 | ppsdds : in std_logic; 20 | y : out gpsif_time_t ); 21 | end gpsif_time; 22 | 23 | architecture beh of gpsif_time is 24 | register variable this : gpsif_time_reg_t reset := gpsif_time_reg_RESET; 25 | register variable this_sync : gpsif_time_sync_t reset := gpsif_time_sync_RESET; 26 | signal a_ra_mod_8 : integer range 0 to 7 := 0; 27 | signal a_ra_mod_16 : integer range 0 to 15 := 0; 28 | signal regf_rd : std_logic_vector(15 downto 0); 29 | signal regf_ra : integer range 0 to 31 := 0; 30 | 31 | begin 32 | pg : process(this,this_sync,gps_d,a,waf,ppsdds) 33 | variable nsec_upcond_60 : boolean; 34 | variable nsec_upcond_61 : boolean; 35 | variable nsec_upcond_62 : boolean; 36 | variable incr_cnt1ms : ufixed(gpsif_cnt1ms_t'high+1 downto 0); 37 | register this when gps_clk = '1' and gps_clk'event reset sync when rst = '1'; 38 | begin 39 | if(this.rt.pps_dly(2) /= this.rt.pps_dly(1)) then 40 | this.rt.nsec_cap := this.rt.nsec; 41 | end if; 42 | this.rt.pps_dly := this.rt.pps_dly(2 downto 0) & ppsdds; 43 | 44 | nsec_upcond_60 := false; 45 | nsec_upcond_61 := false; 46 | nsec_upcond_62 := false; 47 | if (this.rt.round_s = 0) or (this.rt.round_s = 10) then 48 | if(this.rt.round_l = 1) then 49 | nsec_upcond_61 := true; 50 | else nsec_upcond_62 := true; end if; 51 | else 52 | if(this.rt.round_l = 1) then 53 | nsec_upcond_60 := true; 54 | else nsec_upcond_61 := true; end if; 55 | end if; 56 | 57 | -- reset command from clk_sys domain , 58 | -- reset value = 61.09481 * (34 * 8 + 4) = 16862.217 [ns] 59 | -- clk_sys side 32 x gps_clk, gps_clk side 34 x gps_clk 60 | 61 | if(this.rt.inittm = '1') and ((waf mod 8) = 3) then 62 | this.rt.nsec := to_unsigned(16862, 24); 63 | -- reset gps_is2 sys_clk engine 64 | elsif(waf mod 8 = 7) and 65 | (std_logic_vector(this.rt.cnt1ms_g) = "111" & x"fd") then 66 | this.rt.nsec := (others => '0'); 67 | -- 1ms boundary 68 | elsif(nsec_upcond_62) then this.rt.nsec := this.rt.nsec + 62; 69 | elsif(nsec_upcond_61) then this.rt.nsec := this.rt.nsec + 61; 70 | else this.rt.nsec := this.rt.nsec + 60; 71 | end if; 72 | 73 | case this.rt.round_s is 74 | when 20 => this.rt.round_s := 0; 75 | when others => this.rt.round_s := this.rt.round_s + 1; 76 | end case; 77 | case this.rt.round_l is 78 | when 2386 => this.rt.round_l := 0; 79 | when others => this.rt.round_l := this.rt.round_l + 1; 80 | end case; 81 | -- math -- (61 + 2/21 - 1/2387) = (1e6 / 16368) 82 | -- -- hint : 16368 = (16 * 3 * 341) 83 | 84 | -- 1023 counter (nsec count and 1ms count = dual counter) -- 85 | if(this.rt.inittm = '1') and ((waf mod 8) = 3) then 86 | this.rt.cnt1ms_g := (5 => '1', 1 => '1', others => '0'); 87 | -- | | 88 | -- memo 2^5 + 2^1 = hex 22 (dec 34) 89 | elsif(waf mod 8 = 7) then 90 | if(std_logic_vector(this.rt.cnt1ms_g) = "111" & x"fd") then 91 | this.rt.cnt1ms_g := (others => '0'); 92 | this.rt.cnt1msup_g := not this.rt.cnt1msup_g; 93 | else incr_cnt1ms := this.rt.cnt1ms_g + 1; 94 | this.rt.cnt1ms_g := incr_cnt1ms(gpsif_cnt1ms_t'high downto 0); 95 | end if; 96 | end if; 97 | this.rt.inittm := a.inittm; 98 | end process; 99 | 100 | r : bist_RF1 101 | generic map ( WIDTH => 16, DEPTH => 32 ) 102 | port map 103 | (clk => clk, 104 | rst => rst, 105 | bi => ( ctrl => '0', d => '0', en => '0', bist => '0', cmd => "00"), 106 | bo => open, 107 | D => this_sync'register.packetwd, 108 | WA => this_sync'register.packetwa, 109 | WE => this_sync'register.packetwe, 110 | RA0 => regf_ra, 111 | Q0 => regf_rd); 112 | 113 | a_ra_mod_8 <= a.ra mod 8; 114 | a_ra_mod_16 <= a.ra mod 16; 115 | 116 | ps : process(this_sync,this, a, blgps) 117 | variable nsec_upcond_60 : boolean; 118 | variable nsec_upcond_61 : boolean; 119 | variable nsec_upcond_62 : boolean; 120 | variable incr_cnt1ms : ufixed(gpsif_cnt1ms_t'high+1 downto 0); 121 | variable wa_comm_cntup : std_logic; 122 | register this_sync when clk = '1' and clk'event reset sync when rst = '1'; 123 | begin 124 | 125 | if(a.blsp1bit = '0') and (a.blsp2bit = '0') then -- pin direct case 126 | if(this_sync.ppss_dly(1) /= 127 | this_sync.ppss_dly(2)) then 128 | this_sync.nsec := this'register.rt.nsec_cap; 129 | this_sync.cnt1msup_g := this'register.rt.cnt1msup_g; 130 | this_sync.setnsec := '1'; 131 | else 132 | this_sync.setnsec := '0'; 133 | end if; 134 | else -- <-> if{(a.blsp1bit = '1') or (a.blsp2bit = '1')} 135 | -- GPS over bitlink case 136 | if(blgps.en = '1') and (blgps.a = "000010") and 137 | (blgps.tick = '1') then 138 | this_sync.nsec := this_sync.rt.nsec; 139 | this_sync.cnt1msup_g := this_sync.rt.cnt1msup_g; 140 | this_sync.setnsec := '1'; 141 | else 142 | this_sync.setnsec := '0'; 143 | end if; 144 | end if; 145 | 146 | this_sync.ppss_dly := 147 | this_sync.ppss_dly(1 downto 0) & this'register.rt.pps_dly(3); 148 | 149 | nsec_upcond_60 := false; 150 | nsec_upcond_61 := false; 151 | nsec_upcond_62 := false; 152 | if (this_sync.rt.round_s = 0) or (this_sync.rt.round_s = 10) then 153 | if(this_sync.rt.round_l = 1) then 154 | nsec_upcond_61 := true; 155 | else nsec_upcond_62 := true; end if; 156 | else 157 | if(this_sync.rt.round_l = 1) then 158 | nsec_upcond_60 := true; 159 | else nsec_upcond_61 := true; end if; 160 | end if; 161 | 162 | this_sync.packetwa := to_integer(unsigned(blgps.a(5 downto 1))); 163 | 164 | if(blgps.en = '1') then 165 | if (blgps.a(0) = '0') then 166 | this_sync.packetwd(15 downto 8) := blgps.d; 167 | else this_sync.packetwd( 7 downto 0) := blgps.d; end if; 168 | end if; 169 | 170 | if(blgps.en = '1') and (blgps.a(0) = '1') then 171 | this_sync.packetwe := '1'; 172 | else this_sync.packetwe := '0'; 173 | end if; 174 | 175 | 176 | -- regfile read address (from a.ra and this_sync.wa_comm) 177 | if ((((a.ra / 8) mod 4) = 1) and (this_sync.wa_comm mod 4 < 1)) or 178 | ((((a.ra / 8) mod 4) = 2) and (this_sync.wa_comm mod 4 < 2)) or 179 | ((((a.ra / 8) mod 4) = 3) and (this_sync.wa_comm mod 4 < 3)) then 180 | if (a.blsp1bit = '0') then 181 | regf_ra <= ((this_sync.wa_comm / 4) * 4 + (a.ra / 8) + 28) mod 32; 182 | else 183 | regf_ra <= ((this_sync.wa_comm / 4) * 2 + (a.ra / 16) + 30) mod 32; 184 | end if; 185 | else 186 | if (a.blsp1bit = '0') then 187 | regf_ra <= ((this_sync.wa_comm / 4) * 4 + (a.ra / 8) ) mod 32; 188 | else 189 | regf_ra <= ((this_sync.wa_comm / 4) * 2 + (a.ra / 16) ) mod 32; 190 | end if; 191 | end if; 192 | 193 | -- wa_comm state machine 194 | wa_comm_cntup := '0'; 195 | if(blgps.en = '1') and (blgps.a = "000000") then 196 | this_sync.wa_comm := 0; 197 | this_sync.wa_commwait := 0; 198 | if(this_sync.pon_state = '1') then 199 | this_sync.pon_state := '0'; 200 | else 201 | wa_comm_cntup := '1'; end if; 202 | elsif(this_sync.wa_commwait = 42) then 203 | -- gps over bitlink, magic number 5ch * 8cycl + other 2cyc = 42 204 | this_sync.wa_comm := this_sync.wa_comm + 1; 205 | this_sync.wa_commwait := 0; 206 | if((this_sync'register.wa_comm /= 31) and (a.blsp1bit = '0')) or 207 | ((this_sync'register.wa_comm /= 63) and (a.blsp1bit = '1')) then 208 | wa_comm_cntup := '1'; 209 | end if; 210 | elsif( this_sync.wa_comm = 64) or 211 | ((this_sync.wa_comm = 32) and (a.blsp1bit = '0')) then 212 | -- no count up 213 | else -- update wait 214 | if(this_sync.wa_commwait = 63) then 215 | this_sync.wa_commwait := 0; 216 | else this_sync.wa_commwait := this_sync.wa_commwait + 1; end if; 217 | end if; 218 | 219 | if(a.inittm = '1') and (this_sync'register.wa_commwait = 39) then 220 | this_sync.inittmc1(0) := '1'; 221 | this_sync.inittmc2 := this_sync'register.wa_comm; 222 | elsif(blgps.en = '1') and (blgps.a = "000000") then 223 | this_sync.inittmc1(1 downto 0) := 224 | this_sync.inittmc1(0) & '0'; 225 | end if; 226 | 227 | -- if(blgps.en = '1') and (blgps.a(0) = '0') then 228 | if(wa_comm_cntup = '1') then 229 | 230 | -- reset command from clk_sys domain , 231 | -- reset value = 61.09481 * (35 * 8 + 0) = 17106.549 [ns] 232 | -- -> nearest 8ns x n -> 17104 [ns ] (2138 * 8) 233 | 234 | if(this_sync.inittmc3 = '1') then 235 | this_sync.rt.nsec := to_unsigned(17104, 24); 236 | -- reset gps_is2 sys_clk engine 237 | elsif(this_sync.rt.nsec > 999295) then 238 | -- dec999296 = 0xfcf80 -- 1ms boundary 239 | this_sync.rt.nsec := (others => '0'); 240 | elsif(nsec_upcond_62) then 241 | this_sync.rt.nsec := this_sync.rt.nsec + 62 * 8; 242 | elsif(nsec_upcond_61) then 243 | this_sync.rt.nsec := this_sync.rt.nsec + 61 * 8; 244 | else this_sync.rt.nsec := this_sync.rt.nsec + 60 * 8; 245 | end if; 246 | 247 | -- 1023 counter (nsec count and 1ms count = dual counter) -- 248 | if(this_sync.inittmc3 = '1') then 249 | this_sync.rt.cnt1ms_g := (5 => '1', 1 => '1', 0 => '1', 250 | others => '0'); 251 | -- | | 252 | -- memo 2^5 + 2^1 + 2^0= hex 23 (dec 35) 253 | else 254 | if(std_logic_vector(this_sync.rt.cnt1ms_g) = "111" & x"fd") then 255 | this_sync.rt.cnt1ms_g := (others => '0'); 256 | this_sync.rt.cnt1msup_g := not this_sync.rt.cnt1msup_g; 257 | 258 | else incr_cnt1ms := this_sync.rt.cnt1ms_g + 1; 259 | this_sync.rt.cnt1ms_g := incr_cnt1ms(gpsif_cnt1ms_t'high downto 0); 260 | end if; 261 | end if; 262 | 263 | case this_sync.rt.round_s is 264 | when 20 => this_sync.rt.round_s := 0; 265 | when others => this_sync.rt.round_s := this_sync.rt.round_s + 1; 266 | end case; 267 | case this_sync.rt.round_l is 268 | when 2386 => this_sync.rt.round_l := 0; 269 | when others => this_sync.rt.round_l := this_sync.rt.round_l + 1; 270 | end case; 271 | end if; 272 | 273 | if(this_sync'register.wa_commwait = 39) then 274 | this_sync.inittmc3 := a.inittm; 275 | end if; 276 | 277 | end process; 278 | -- connect outputs 279 | y.nsec <= this_sync'register.nsec; 280 | y.seq <= (others => '0'); 281 | y.mscnt <= this_sync'register.cnt1msup_g; 282 | y.setnsec <= this_sync'register.setnsec; 283 | y.d <= regf_rd((15 - 2 * a_ra_mod_8) downto 284 | (14 - 2 * a_ra_mod_8)) 285 | when (a.blsp1bit = '0') else 286 | (regf_rd(15 - a_ra_mod_16) & "0"); -- 1b form -> 2b form 287 | y.wa <= this_sync'register.wa_comm mod 4; 288 | end beh; 289 | -------------------------------------------------------------------------------- /gpsif_top.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Brief GPSIF Spec. Written on Aug. 23, 2017 by Fumio Arakawa 3 | -------------------------------------------------------------------------------- 4 | --------- Address map (32b address, 4 byte stride for channel address) --------- 5 | -- abcc0000 : Base address on CPU bus 6 | -- abcc0000 + ch : C/A code shift, PNCO inc., DMA channel 7 | -- abcc0020 + ch : G2 shift & Acquisition mode, Channel activation 8 | -- abcc0040 + ch : PNCO 9 | -- abcc0060 : S/W reset 10 | -- abcc0100 +8*ch +N : Output buffer (N: 0-5 for EI,EQ,PI,PQ,LI,LQ) 11 | -- abcc0200 : GPSIF status 12 | -- abcc0204 : Input buffer from CPU bus 13 | 14 | -------------------------------- Bit assignment -------------------------------- 15 | -- 1. S/W reset 16 | -- 31 : 0 17 | -- 8 : bitlink case sample bit mode 18 | -- 0: 2 bits/sample. 1: 1 bit sample 19 | -- 1- 0 : input mode ( 20 | -- 00: from I/O port, 01: from CPU bus, 10: from bitlink 21 | -- (Currently, other bits are used to dump signals for debug on FPGA) 22 | -- 2. Channel Initialization 23 | -- 1. C/A code shift (direct, inc./plus/minus), PNCO inc., DMA channel 24 | -- 31 : direct write of C/A code shift & DMA channel (0: Enable, 1: Disable) 25 | -- 30-29 : C/A code shift update type ( NOP, INC, PLS, MNS ) 26 | -- 28 : PNCO update (0: Disable, 1: Enable) 27 | -- 27 : shift inc. code set (0: Disable, 1: Enable) 28 | -- 26-24 : shift inc. code 29 | -- 000 : + 1 100 : + 4 30 | -- 001 : + 8 101 : -24 31 | -- 010 : +16 110 : -16 32 | -- 011 : +24 111 : - 8 33 | -- 23 : PNCO inc. code set (0: Disable, 1: Enable) 34 | -- 22-20 : PNCO inc. code 35 | -- 000 : 1 100 : 16 36 | -- 001 : 2 101 : 32 37 | -- 010 : 4 110 : 64 38 | -- 011 : 8 111 : 128 39 | -- 19-14 : DMA channel 40 | -- 13- 0 : C/A code shift (for direct write) 41 | -- 2. PNCO direct write 42 | -- 28- 0 : PNCO (28 bit signed number, HW ignores bit 31-30) 43 | -- 3. G2 shift & Acquisition mode 44 | -- 31 : Acquisition mode (0: Disable, 1: Enable) 45 | -- 9- 0 : G2 shift 46 | -- 4. GPSIF status register 47 | -- 29-16 : Channel status (0:IDL, 1:ACQ, 2:RDY, 3:VLD) 48 | -- 23-22 : #3 49 | -- 29-28 : #6 21-20 : #2 50 | -- 27-26 : #5 19-18 : #1 51 | -- 25-24 : #4 17-16 : #0 52 | -- 14- 8 : Channel is running or not (0:ready, 1:run) 53 | -- 11 : #3 54 | -- 14 : #6 10 : #2 55 | -- 13 : #5 9 : #1 56 | -- 12 : #4 8 : #0 57 | -- 0 : Input buffer status (0:BUSY, 1:FILL) 58 | 59 | -------------------------------- control by S/W -------------------------------- 60 | -- 1. S/W reset 61 | 62 | -- S/W reset initializes GPSIF. 63 | -- - Input mode is specified by bit 31, and 0 & 1 correspond to from I/O port & CPU bus. 64 | -- - All of channels are set to IDL. 65 | -- - Input buffer is cleared by initializing read scope & write pointers. 66 | -- - Reset 1-ms counter that counts number of data of 1023*16 for 1 ms. 67 | -- (The counter consists of common higher 11-bit one that skips 1023*2 and 1023*2+1, 68 | -- and lower 3-bit one just to count 8 for each 8 data processing.) 69 | 70 | -- 2. Each Channel initialization and updates 71 | 72 | -- For Tracking 73 | -- 1) Direct write of C/A code shift of acquired satellite 74 | -- The value is the 1-ms counter value corresponding to the last data of the 1-ms period of the acquired satellite. 75 | -- 2) Direct write of PNCO of the acquired satellite 76 | -- 3) Write of G2 shift of the acquired satellite w/ disabling acquisition. The write makes the channel RDY. 77 | -- The initialized channel starts running after the higher 11-bits of the C/A code shift and the 1-ms counter match. 78 | -- 4) Write PLS/MNS mode if C/A code shift is to be adjusted with +-1 79 | -- (H/W adjust the shift as early as possible w/ keeping carrier NCO phase.) 80 | -- 5) Write new PNCO if it is to be adjusted. 81 | -- (H/W changes the PNCO as early as possible. The carrier NCO phase is naturally kept.) 82 | 83 | -- For Serial Acquisition (Not use acquisition mode) 84 | -- 1) Direct write of initial C/A code shift of each channel 85 | -- 2) Direct write of initial PNCO 86 | -- 3) Write of G2 shift of a satellite w/ disabling acquisition. The write makes the channel RDY. 87 | -- 4) Increment PNCO to scan Doppler shift range of +-10 kHz 88 | -- (H/W initializes carrier NCO phase to 0 when it increment the PNCO. 89 | -- Then, each evaluation starts w/ the same carrier NCO phase.) 90 | -- 5) Increment C/A code shift to scan all the shift range 91 | -- (H/W increment the PNCO and C/A code shift at the 1-ms boundary of the channel. 92 | -- So, the control must be done during the last 1-ms evaluation of the channel.) 93 | -- 6) Write of G2 shift of another satellite w/ disabling acquisition. 94 | 95 | -- For FFT Acquisition (Use acquisition mode) 96 | -- 1) Direct write of initial PNCO 97 | -- 2) Set acquisition mode enable. The write makes the channel RDY. (G2 shift is not used) 98 | -- 3) The initialized channel starts running when the 1-ms counter becomes 0. 99 | -- (The initial values of C/A code shift and 1-ms counter matches, and the next counter value is 0.) 100 | -- 4) Increment PNCO to scan Doppler shift range of +-10 kHz 101 | 102 | -- 3. Data input 103 | 104 | -- From I/O port 105 | -- 1) Write data w/ setting bit 31 to be 0 to S/W reset address. 106 | -- Default input mode is to use I/O port. Nothing is to be done after H/W reset. 107 | -- From CPU bus 108 | -- 1) Write data w/ setting bit 31 to be 1 to S/W reset address. 109 | -- 2) CPU bus master reads GPSIF status register to check input buffer status BUSY or not, and 110 | -- wait until the status becomes FILL. 111 | -- 3) After it becomes FILL, the CPU bus master writes 16*32 bits of data. 112 | -- Input cycles must be more than 56 (7ch*8cycles) per 16 CPU bus operations for 7 channel case. 113 | -- Is is safe to write data every 4 cycles or less. (4*16 = 64 > 56) 114 | 115 | -- 4. Read evaluation result 116 | 117 | -- By CPU bus master 118 | -- 1) CPU bus master checks each channel status by reading GPSIF status register. 119 | -- 2) If the status is VLD, it reads valid results in output buffers. 120 | -- - The results of each channel are six data of EI,EQ,PI,PQ,LI, and LQ. 121 | -- H/W changes the status to RDY after reading the LQ. 122 | -- So, the LQ should be read last. 123 | -- - GPSIF has output buffers that is separated from accumulating buffers. 124 | -- Then, the results in the output buffers are valid for 1 ms. 125 | -- - H/W set the fail flag of each channel 126 | -- when H/W observes a read access while the status is RDY (read-before-write), 127 | -- or H/W writes a new result while the status is VLD (write-before-read). 128 | -- (Currently, the fail bits are not assigned to GPSIF status register yet.) 129 | -- By DMAC 130 | -- 1) When DMAC get the DMA channel number from GPSIF, it reads the results. 131 | -- - GPSIF output the DMA channel assigned to each channel to DMAC when the results of the channel become valid. 132 | -- So, the DMAC does not have to check the output validity. 133 | 134 | --------------------------------- H/W behavior --------------------------------- 135 | -- 0. H/W reset 136 | -- H/W reset initializes GPSIF. Default input mode is from I/O port. The others are the same as the S/W reset. 137 | 138 | -- 2. Input buffer write 139 | -- From I/O port, GPSIF has a buffer consisting of 4 sets of 8 data. The write uses a special clock synchronized 140 | -- to the I/O port. So, the write pointer and write enable signal are clocked by the special clock. The GPSIF 141 | -- processing is faster than the input write. So, the write is always possible. The higher 2 bits of the write 142 | -- pointer is passed to main body of the GPSIF. For an asynchronous pass, the 2 bits changes with a sequence of 143 | -- 00 => 01 => 11 => 10 => 00. Then, the 2-bit code is always correct even when the signal change timing is 144 | -- slightly different. (Avoiding 01 => 10 or 10 => 01 is important.) 145 | 146 | -- From CPU bus, the GPSIF has a buffer consisting of 32 sets of 8 data assuming a 512 bit packet for the data. 147 | -- GPSIF clear the input buffer status bit of the GPSIF status register to show it is BUSY when the write pointer 148 | -- returns to 0, until read scope pointer points the last scope. CPU bus master must wait until the bit is set 149 | -- for writing new input data. Since the last scope consists of the last and first 8 data and the processing of 150 | -- the scope requires 7*8 = 56 cycles, and 512 bit buffer filling takes 512/32 = 16 CPU bus operations, the bus 151 | -- master must not issue the last input data write within the 56 cycles. Is is safe to write data every 4 cycles 152 | -- or less. Assuming future data input from ring bus, it takes 512/8 = 64 ring bus cycles or more, and no 153 | -- restriction is necessary to keep the input data. 154 | 155 | -- 3. Input buffer read by GPSIF H/W 156 | -- Input buffer is divided into multiple sets of 8 data, and two consecutive sets are specified by the read scope 157 | -- pointer as a current input data scope. Then, a 4-bit read pointer that is lower 4 bits of C/A code shift of each 158 | -- channel can specify any 8 data in the scope. So, all the channels can share the input buffer with different C/A 159 | -- code shift. However, this is not true when the C/A code shift changes. The direct write is for initialization, 160 | -- and it must be done while the channel is IDL. The change by INC/PLS mode requires a scope skip to ignore data 161 | -- between the last and new 1 ms. For negative INC, HW skips data of 1022*16 + (negative)INC. If the new shift can 162 | -- use the same scope, HW does not skip the scope. For MNS mode, HW uses the same scope twice if the scope is 163 | -- changed. If the read scope reaches to the writing entry of the input buffer, GPSIF stall processing of the data. 164 | -------------------------------------------------------------------------------- 165 | library ieee; 166 | use ieee.std_logic_1164.all; 167 | use work.gpsif_pack.all; 168 | use work.gpsif_sub_pack.all; 169 | use work.cpu2j0_pack.all; 170 | use work.ring_bus_pack.all; 171 | use work.rbus_pack.all; 172 | use work.bist_pack.all; 173 | use work.util_pack.all; 174 | use work.attr_pack.all; 175 | 176 | entity gpsif_top is 177 | generic ( GPSIF_NC : integer := 7; 178 | ANGLE_INI_OLD : boolean := false ); 179 | port ( 180 | clk : in std_logic; 181 | rst : in std_logic; 182 | gps_clk : in std_logic; 183 | gps_d : in std_logic_vector(1 downto 0); 184 | ppsdds : in std_logic; 185 | blgps : in blgps_t; 186 | dma : out dma_req_t; 187 | intrpt : out std_logic; 188 | bi : in bist_scan_t; 189 | bo : out bist_scan_t; 190 | ring_i : in rbus_9b; 191 | ring_o : out rbus_9b; 192 | bus_clk : in std_logic; 193 | db_i : in cpu_data_o_t; 194 | db_o : out cpu_data_i_t ); 195 | attribute soc_port_irq of intrpt : signal is true; 196 | end entity; 197 | 198 | architecture arch of gpsif_top is 199 | -- gpsif ports 200 | signal tgt_o : cpu_data_i_t; 201 | signal tgt_i : gpsif_tgt_i_t; 202 | signal dev_i : rbus_dev_i_t; 203 | signal dev_o : rbus_dev_o_t; 204 | signal buf_io : gpsif_buf_i_t; 205 | signal ra_io : gpsif_buf_ct_t; 206 | signal buf_bus : gpsif_i_t; 207 | signal buf_waf : gpsif_buf_rw_t; 208 | signal time_i : gpsif_time_t; 209 | signal gpsif_o : gpsif_o_t; 210 | signal bs0 : bist_scan_t; 211 | signal gps_clkbf : std_logic; 212 | signal ring_o_dbg : rbus_9b; 213 | 214 | begin 215 | ring_o <= ring_o_dbg; 216 | g : gpsif 217 | generic map ( GPSIF_NC => GPSIF_NC, 218 | ANGLE_INI_OLD => ANGLE_INI_OLD ) 219 | port map ( 220 | clk => clk, 221 | rst => rst, 222 | bi => bi, 223 | bo => bs0, 224 | ring_i => ring_i, -- to monitor ring bus 225 | ring_o => ring_o_dbg, -- to monitor ring bus 226 | tgt_o => tgt_o, 227 | tgt_i => tgt_i, 228 | dev_o => dev_o, -- output to ring bus 229 | dev_i => dev_i, -- input from ring bus 230 | buf_io => buf_io, -- wp(write pointer), sgin, magnitude 231 | time_i => time_i, 232 | ra_io => ra_io, 233 | buf_bus => buf_bus, 234 | gpsif_o => gpsif_o, -- rp(read pointer) 235 | dma => dma 236 | ); 237 | a : rbus_adp 238 | port map ( 239 | clk => clk, 240 | rst => rst, 241 | -- sw_rst => gpsif_o.rst, 242 | ring_i => ring_i, 243 | -- ring_o => ring_o, 244 | ring_o => ring_o_dbg, 245 | dev_o => dev_o, 246 | dev_i => dev_i 247 | ); 248 | b : gpsif_buf 249 | port map ( 250 | clk => clk, 251 | rst => rst, 252 | gps_clk => gps_clkbf, 253 | gps_d => gps_d, 254 | a => ra_io, 255 | y => buf_io, 256 | waf => buf_waf 257 | ); 258 | c : gpsif_db 259 | port map ( 260 | clk => bus_clk, 261 | rst => rst, 262 | bi => bs0, 263 | bo => bo, 264 | db_i => db_i, 265 | db_o => db_o, 266 | tgt_o => tgt_o, 267 | tgt_i => tgt_i, 268 | time_i => time_i, 269 | intrpt => intrpt, 270 | a => gpsif_o, 271 | y => buf_bus 272 | ); 273 | d : global_buffer 274 | port map ( 275 | i => gps_clk, 276 | o => gps_clkbf 277 | ); 278 | e : gpsif_time 279 | port map ( 280 | clk => clk, 281 | rst => rst, 282 | gps_clk => gps_clkbf, 283 | gps_d => gps_d, 284 | a => ra_io, 285 | waf => buf_waf, 286 | ppsdds => ppsdds, 287 | blgps => blgps, 288 | y => time_i 289 | ); 290 | 291 | end architecture; 292 | -------------------------------------------------------------------------------- /rbus_adp.vhm: -------------------------------------------------------------------------------- 1 | 2 | ---------------------------- GPS digital part (ring bus adaptor) ---------------------------- 3 | -- written on 2016/12/14 by F. Arakawa -- 4 | --------------------------------------------------------------------------------------------- 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use work.ring_bus_pack.all; 8 | use work.rbus_pack.all; 9 | 10 | entity rbus_adp is 11 | generic (OWN_CH : integer := RNG_CH_GPS); -- default 12 | port (clk : in std_logic; 13 | rst : in std_logic; 14 | -- sw_rst : in boolean; 15 | ring_i : in rbus_9b; 16 | ring_o : out rbus_9b; 17 | dev_o : in rbus_dev_o_t; -- from device 18 | dev_i : out rbus_dev_i_t); -- to device 19 | end rbus_adp; 20 | 21 | architecture beh of rbus_adp is 22 | 23 | type rbus_in_t is -- input word type 24 | (BC, -- input word is BROADCAST cmd 25 | BSY, -- input word is BUSY cmd 26 | FW, -- input word is to be forwarded to successor 27 | WT, -- input word is to be written to device 28 | DTI);-- input word is data 29 | type rbus_wd_t is (CM, CH, DT); -- command, broadcast channel, or data 30 | type rbus_fwd_t is (FWD, SND); -- forward or send 31 | type rbus_typ_t is array (rbus_in_t range BC to DTI) of boolean; 32 | type rbus_reg_t is record 33 | snd,rcv : rbus_wd_t; 34 | fwd : rbus_fwd_t; 35 | dly,ring_o : rbus_word_9b; 36 | dly_v : boolean; 37 | end record; 38 | constant rbus_reg_RESET : rbus_reg_t := ( 39 | snd => CM, dly => IDLE_9b, dly_v => false, 40 | rcv => CM, ring_o => IDLE_9b, fwd => FWD 41 | ); 42 | register variable this : rbus_reg_t reset := rbus_reg_RESET; 43 | 44 | begin 45 | p0 : process(this,ring_i,dev_o) 46 | register this when clk = '1' and clk'event reset sync when rst = '1'; 47 | 48 | variable dev_dt,cmd_nop,stall_wt,stall_fw,dev_i_v,dev_i_ack : boolean; 49 | variable typ : rbus_typ_t; 50 | variable dev_i_wd, dev_o_wd : rbus_word_9b; 51 | variable cmd : rbus_cmd; 52 | variable hop : cmd_hops; 53 | begin 54 | -- device output setup ( add fr bit and packet of cmd,hop and channel) 55 | dev_dt := this.snd = DT and dev_o.v; 56 | if dev_o.v then case this.snd is 57 | when CM => dev_o_wd := cmd_word_9b(BROADCAST,1); this.snd := CH; 58 | when CH => dev_o_wd := data_word_9b(2**dev_o.ch); this.snd := DT; 59 | when DT => dev_o_wd := data_word_9b(dev_o.d); this.snd := DT; 60 | end case; else dev_o_wd := data_word_9b(dev_o.d); this.snd := CM; end if; 61 | -- input select 62 | if this.dly_v then dev_i_wd := this.dly; 63 | else dev_i_wd := ring_i.word; end if; 64 | -- input cmd type & hop count check 65 | if dev_i_wd.fr = '1' then 66 | cmd := to_cmd (dev_i_wd.d); 67 | hop := to_hops(dev_i_wd.d); 68 | typ(BC) := cmd = BROADCAST; 69 | typ(BSY):= cmd = BUSY; 70 | typ(FW) := cmd /= IDLE and hop/2 /= 0; -- hop>1 71 | typ(WT) :=((cmd /= IDLE and hop = 1) or typ(BC)); -- hop=1 72 | -- decrement hop after the check 73 | if hop /= 0 then hop := hop -1; dev_i_wd := cmd_word_9b(cmd,hop); end if; 74 | else typ := (others => false); end if; 75 | typ(DTI) := typ(BSY) or dev_i_wd.fr = '0'; -- data words 76 | -- to device (check cmd and channel, and send data) 77 | dev_i_v := false; 78 | case this.rcv is 79 | when CM => if typ(WT) then if typ(BC) then this.rcv := CH; 80 | else this.rcv := DT; end if; end if; 81 | when CH => if dev_i_wd.d(OWN_CH)= '1' then this.rcv := DT; 82 | else this.rcv := CM; end if; 83 | when DT => if not typ(DTI) then this.rcv := CM; end if; 84 | dev_i_v := dev_i_wd.fr = '0'; -- Input is valid data. 85 | end case; 86 | stall_wt := dev_i_v and dev_o.bsy; -- So stall occurs if device is busy. 87 | -- to successor 88 | -- output cmd type check 89 | if this.ring_o.fr = '1' then 90 | cmd := to_cmd(this.ring_o.d); 91 | cmd_nop := cmd = IDLE or cmd = BUSY; 92 | else cmd_nop := false; end if; 93 | -- Toggle output mode if possible: FWD <=> SND 94 | stall_fw := false; 95 | dev_i_ack := false; 96 | if ring_i.stall = '0' or cmd_nop then case this.fwd is -- ring_o can be updated 97 | when FWD => if typ(DTI) then if stall_wt then this.ring_o := cmd_word_9b(BUSY,0); 98 | else this.ring_o := dev_i_wd; end if; -- continue 99 | elsif dev_o.v then this.fwd := SND; this.ring_o := dev_o_wd; stall_fw := typ(FW); -- mode toggle 100 | elsif typ(FW) then this.ring_o := dev_i_wd; -- new forward 101 | else this.fwd := SND; this.ring_o := IDLE_9b; end if; -- send mode check valid 102 | when SND => if dev_dt then dev_i_ack:=true; this.ring_o := dev_o_wd; stall_fw := typ(FW); -- continue, data is sent 103 | elsif typ(FW) then this.fwd := FWD; this.ring_o := dev_i_wd; -- mode toggle 104 | elsif dev_o.v then this.fwd := SND; this.ring_o := dev_o_wd; stall_fw := typ(FW); -- new send 105 | else this.ring_o := IDLE_9b; end if; end case; 106 | else stall_fw := typ(FW); end if; -- to be forwarded, but cannot 107 | -- keep ring_i if it is not used yet 108 | if not this.dly_v and (stall_wt or stall_fw) then this.dly := ring_i.word; end if; 109 | this.dly_v := stall_wt or stall_fw; 110 | dev_i.d <= dev_i_wd.d; 111 | dev_i.v <= dev_i_v; 112 | dev_i.ack <= dev_i_ack; 113 | -- SW reset 114 | -- if sw_rst then this := rbus_reg_RESET; end if; 115 | end process; 116 | -- stall ring_i if the previous value is kept in this.dly 117 | ring_o.stall <= '1' when this'register.dly_v else '0'; 118 | ring_o.word <= this'register.ring_o; 119 | end beh; 120 | -------------------------------------------------------------------------------- /rbus_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.ring_bus_pack.all; 5 | 6 | package rbus_pack is 7 | -- added by FA 8 | constant RNG_CH_DSP : integer := 0; 9 | constant RNG_CH_GPS : integer := 1; 10 | type rbus_dev_o_t is record 11 | d : std_logic_vector(8 downto 0); 12 | v,bsy : boolean; 13 | ch : integer range 0 to 8; 14 | end record; 15 | type rbus_dev_i_t is record 16 | d : std_logic_vector(8 downto 0); 17 | v,ack : boolean; 18 | end record; 19 | component rbus_adp is 20 | generic (OWN_CH : integer := RNG_CH_GPS); -- default 21 | port (clk : in std_logic; 22 | rst : in std_logic; 23 | -- sw_rst : in boolean; 24 | ring_i : in rbus_9b; 25 | ring_o : out rbus_9b; 26 | dev_o : in rbus_dev_o_t; -- from device 27 | dev_i : out rbus_dev_i_t); -- to device 28 | end component; 29 | 30 | end package; 31 | -------------------------------------------------------------------------------- /tests/gpsif_db_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.71 (w)1999-2016 BSI 3 | [*] Fri Oct 28 22:20:49 2016 4 | [*] 5 | [dumpfile] "/Users/fumio/VM/share/current/soc_top/components/gps_if2/tests/gpsif_db_tb.ghw" 6 | [dumpfile_mtime] "Fri Oct 28 13:50:34 2016" 7 | [dumpfile_size] 92689138 8 | [savefile] "/Users/fumio/VM/share/current/soc_top/components/gps_if2/tests/gspif_db_tb.gtkw" 9 | [timestart] 0 10 | [size] 1918 552 11 | [pos] 0 -1 12 | *-37.678806 909000000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] top. 14 | [treeopen] top.gpsif_db_tb. 15 | [treeopen] top.gpsif_db_tb.g. 16 | [treeopen] top.gpsif_db_tb.g.g. 17 | [treeopen] top.gpsif_db_tb.g.g.a. 18 | [treeopen] top.gpsif_db_tb.g.g.acm. 19 | [treeopen] top.gpsif_db_tb.g.g.acm.a. 20 | [treeopen] top.gpsif_db_tb.g.g.acm.y. 21 | [treeopen] top.gpsif_db_tb.g.g.cacode_i. 22 | [treeopen] top.gpsif_db_tb.g.g.cdgen.a. 23 | [treeopen] top.gpsif_db_tb.g.g.cdgen.this_c. 24 | [treeopen] top.gpsif_db_tb.g.g.cdgen.this_r. 25 | [treeopen] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft. 26 | [treeopen] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft. 27 | [treeopen] top.gpsif_db_tb.g.g.regfile_o. 28 | [treeopen] top.gpsif_db_tb.g.g.regfile_o.angle. 29 | [treeopen] top.gpsif_db_tb.g.g.sum.this_r. 30 | [treeopen] top.gpsif_db_tb.g.g.target_i. 31 | [treeopen] top.gpsif_db_tb.g.g.this_c. 32 | [treeopen] top.gpsif_db_tb.g.g.this_r. 33 | [treeopen] top.gpsif_db_tb.g.gpsif_i. 34 | [treeopen] top.gpsif_db_tb.g.gpsif_o. 35 | [treeopen] top.gpsif_db_tb.g.target_i. 36 | [treeopen] top.gpsif_db_tb.g.target_o. 37 | [sst_width] 245 38 | [signals_width] 175 39 | [sst_expanded] 1 40 | [sst_vpaned_height] 303 41 | @28 42 | top.gpsif_db_tb.g.rst 43 | top.gpsif_db_tb.g.clk 44 | top.gpsif_db_tb.g.gpsif_i.wp 45 | top.gpsif_db_tb.g.g.this_r.init 46 | @22 47 | #{top.gpsif_db_tb.g.g.regfile_o.angle.angle[29:0]} top.gpsif_db_tb.g.g.regfile_o.angle.angle[29] top.gpsif_db_tb.g.g.regfile_o.angle.angle[28] top.gpsif_db_tb.g.g.regfile_o.angle.angle[27] top.gpsif_db_tb.g.g.regfile_o.angle.angle[26] top.gpsif_db_tb.g.g.regfile_o.angle.angle[25] top.gpsif_db_tb.g.g.regfile_o.angle.angle[24] top.gpsif_db_tb.g.g.regfile_o.angle.angle[23] top.gpsif_db_tb.g.g.regfile_o.angle.angle[22] top.gpsif_db_tb.g.g.regfile_o.angle.angle[21] top.gpsif_db_tb.g.g.regfile_o.angle.angle[20] top.gpsif_db_tb.g.g.regfile_o.angle.angle[19] top.gpsif_db_tb.g.g.regfile_o.angle.angle[18] top.gpsif_db_tb.g.g.regfile_o.angle.angle[17] top.gpsif_db_tb.g.g.regfile_o.angle.angle[16] top.gpsif_db_tb.g.g.regfile_o.angle.angle[15] top.gpsif_db_tb.g.g.regfile_o.angle.angle[14] top.gpsif_db_tb.g.g.regfile_o.angle.angle[13] top.gpsif_db_tb.g.g.regfile_o.angle.angle[12] top.gpsif_db_tb.g.g.regfile_o.angle.angle[11] top.gpsif_db_tb.g.g.regfile_o.angle.angle[10] top.gpsif_db_tb.g.g.regfile_o.angle.angle[9] top.gpsif_db_tb.g.g.regfile_o.angle.angle[8] top.gpsif_db_tb.g.g.regfile_o.angle.angle[7] top.gpsif_db_tb.g.g.regfile_o.angle.angle[6] top.gpsif_db_tb.g.g.regfile_o.angle.angle[5] top.gpsif_db_tb.g.g.regfile_o.angle.angle[4] top.gpsif_db_tb.g.g.regfile_o.angle.angle[3] top.gpsif_db_tb.g.g.regfile_o.angle.angle[2] top.gpsif_db_tb.g.g.regfile_o.angle.angle[1] top.gpsif_db_tb.g.g.regfile_o.angle.angle[0] 48 | #{top.gpsif_db_tb.g.g.regfile_o.angle.pnco[29:0]} top.gpsif_db_tb.g.g.regfile_o.angle.pnco[29] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[28] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[27] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[26] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[25] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[24] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[23] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[22] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[21] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[20] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[19] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[18] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[17] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[16] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[15] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[14] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[13] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[12] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[11] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[10] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[9] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[8] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[7] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[6] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[5] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[4] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[3] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[2] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[1] top.gpsif_db_tb.g.g.regfile_o.angle.pnco[0] 49 | @28 50 | top.gpsif_db_tb.g.gpsif_o.a 51 | top.gpsif_db_tb.g.g.this_r.st 52 | top.gpsif_db_tb.g.g.this_r.ready 53 | top.gpsif_db_tb.g.g.this_r.rd 54 | top.gpsif_db_tb.g.g.this_r.nc 55 | top.gpsif_db_tb.g.g.this_r.nd 56 | top.gpsif_db_tb.g.g.this_r.cnt1ms 57 | #{top.gpsif_db_tb.g.g.a.d[1:0]} top.gpsif_db_tb.g.g.a.d[1] top.gpsif_db_tb.g.g.a.d[0] 58 | top.gpsif_db_tb.g.g.sum_i.q 59 | top.gpsif_db_tb.g.g.acm_i.q 60 | top.gpsif_db_tb.g.g.sum_i.i 61 | top.gpsif_db_tb.g.g.acm_i.i 62 | top.gpsif_db_tb.g.g.acm.this_r.ch 63 | top.gpsif_db_tb.g.g.cdgen.a.ch 64 | @800022 65 | #{top.gpsif_db_tb.g.g.this_r.ch_st[0:6]} top.gpsif_db_tb.g.g.this_r.ch_st[0] top.gpsif_db_tb.g.g.this_r.ch_st[1] top.gpsif_db_tb.g.g.this_r.ch_st[2] top.gpsif_db_tb.g.g.this_r.ch_st[3] top.gpsif_db_tb.g.g.this_r.ch_st[4] top.gpsif_db_tb.g.g.this_r.ch_st[5] top.gpsif_db_tb.g.g.this_r.ch_st[6] 66 | @28 67 | top.gpsif_db_tb.g.g.this_r.ch_st[0] 68 | top.gpsif_db_tb.g.g.this_r.ch_st[1] 69 | top.gpsif_db_tb.g.g.this_r.ch_st[2] 70 | top.gpsif_db_tb.g.g.this_r.ch_st[3] 71 | top.gpsif_db_tb.g.g.this_r.ch_st[4] 72 | top.gpsif_db_tb.g.g.this_r.ch_st[5] 73 | top.gpsif_db_tb.g.g.this_r.ch_st[6] 74 | @1001200 75 | -group_end 76 | @28 77 | top.gpsif_db_tb.g.g.cdgen.a.even 78 | top.gpsif_db_tb.g.g.cdgen.a.set 79 | @22 80 | #{top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][9:0]} top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][9] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][8] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][7] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][6] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][5] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][4] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][3] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][2] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][1] top.gpsif_db_tb.g.g.cdgen.this_r.g1sft[0][0] 81 | #{top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][9:0]} top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][9] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][8] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][7] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][6] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][5] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][4] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][3] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][2] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][1] top.gpsif_db_tb.g.g.cdgen.this_r.g2sft[0][0] 82 | @28 83 | #{top.gpsif_db_tb.g.g.cdgen.this_c.code[2:0]} top.gpsif_db_tb.g.g.cdgen.this_c.code[2] top.gpsif_db_tb.g.g.cdgen.this_c.code[1] top.gpsif_db_tb.g.g.cdgen.this_c.code[0] 84 | #{top.gpsif_db_tb.g.g.cdgen.this_r.code[2:0]} top.gpsif_db_tb.g.g.cdgen.this_r.code[2] top.gpsif_db_tb.g.g.cdgen.this_r.code[1] top.gpsif_db_tb.g.g.cdgen.this_r.code[0] 85 | @22 86 | #{top.gpsif_db_tb.g.g.acm_o.wd[27:0]} top.gpsif_db_tb.g.g.acm_o.wd[27] top.gpsif_db_tb.g.g.acm_o.wd[26] top.gpsif_db_tb.g.g.acm_o.wd[25] top.gpsif_db_tb.g.g.acm_o.wd[24] top.gpsif_db_tb.g.g.acm_o.wd[23] top.gpsif_db_tb.g.g.acm_o.wd[22] top.gpsif_db_tb.g.g.acm_o.wd[21] top.gpsif_db_tb.g.g.acm_o.wd[20] top.gpsif_db_tb.g.g.acm_o.wd[19] top.gpsif_db_tb.g.g.acm_o.wd[18] top.gpsif_db_tb.g.g.acm_o.wd[17] top.gpsif_db_tb.g.g.acm_o.wd[16] top.gpsif_db_tb.g.g.acm_o.wd[15] top.gpsif_db_tb.g.g.acm_o.wd[14] top.gpsif_db_tb.g.g.acm_o.wd[13] top.gpsif_db_tb.g.g.acm_o.wd[12] top.gpsif_db_tb.g.g.acm_o.wd[11] top.gpsif_db_tb.g.g.acm_o.wd[10] top.gpsif_db_tb.g.g.acm_o.wd[9] top.gpsif_db_tb.g.g.acm_o.wd[8] top.gpsif_db_tb.g.g.acm_o.wd[7] top.gpsif_db_tb.g.g.acm_o.wd[6] top.gpsif_db_tb.g.g.acm_o.wd[5] top.gpsif_db_tb.g.g.acm_o.wd[4] top.gpsif_db_tb.g.g.acm_o.wd[3] top.gpsif_db_tb.g.g.acm_o.wd[2] top.gpsif_db_tb.g.g.acm_o.wd[1] top.gpsif_db_tb.g.g.acm_o.wd[0] 87 | #{top.gpsif_db_tb.g.g.target_i.d[31:0]} top.gpsif_db_tb.g.g.target_i.d[31] top.gpsif_db_tb.g.g.target_i.d[30] top.gpsif_db_tb.g.g.target_i.d[29] top.gpsif_db_tb.g.g.target_i.d[28] top.gpsif_db_tb.g.g.target_i.d[27] top.gpsif_db_tb.g.g.target_i.d[26] top.gpsif_db_tb.g.g.target_i.d[25] top.gpsif_db_tb.g.g.target_i.d[24] top.gpsif_db_tb.g.g.target_i.d[23] top.gpsif_db_tb.g.g.target_i.d[22] top.gpsif_db_tb.g.g.target_i.d[21] top.gpsif_db_tb.g.g.target_i.d[20] top.gpsif_db_tb.g.g.target_i.d[19] top.gpsif_db_tb.g.g.target_i.d[18] top.gpsif_db_tb.g.g.target_i.d[17] top.gpsif_db_tb.g.g.target_i.d[16] top.gpsif_db_tb.g.g.target_i.d[15] top.gpsif_db_tb.g.g.target_i.d[14] top.gpsif_db_tb.g.g.target_i.d[13] top.gpsif_db_tb.g.g.target_i.d[12] top.gpsif_db_tb.g.g.target_i.d[11] top.gpsif_db_tb.g.g.target_i.d[10] top.gpsif_db_tb.g.g.target_i.d[9] top.gpsif_db_tb.g.g.target_i.d[8] top.gpsif_db_tb.g.g.target_i.d[7] top.gpsif_db_tb.g.g.target_i.d[6] top.gpsif_db_tb.g.g.target_i.d[5] top.gpsif_db_tb.g.g.target_i.d[4] top.gpsif_db_tb.g.g.target_i.d[3] top.gpsif_db_tb.g.g.target_i.d[2] top.gpsif_db_tb.g.g.target_i.d[1] top.gpsif_db_tb.g.g.target_i.d[0] 88 | #{top.gpsif_db_tb.g.g.cacode_i.wen[0:6]} top.gpsif_db_tb.g.g.cacode_i.wen[0] top.gpsif_db_tb.g.g.cacode_i.wen[1] top.gpsif_db_tb.g.g.cacode_i.wen[2] top.gpsif_db_tb.g.g.cacode_i.wen[3] top.gpsif_db_tb.g.g.cacode_i.wen[4] top.gpsif_db_tb.g.g.cacode_i.wen[5] top.gpsif_db_tb.g.g.cacode_i.wen[6] 89 | #{top.gpsif_db_tb.g.g.cacode_i.indata[9:0]} top.gpsif_db_tb.g.g.cacode_i.indata[9] top.gpsif_db_tb.g.g.cacode_i.indata[8] top.gpsif_db_tb.g.g.cacode_i.indata[7] top.gpsif_db_tb.g.g.cacode_i.indata[6] top.gpsif_db_tb.g.g.cacode_i.indata[5] top.gpsif_db_tb.g.g.cacode_i.indata[4] top.gpsif_db_tb.g.g.cacode_i.indata[3] top.gpsif_db_tb.g.g.cacode_i.indata[2] top.gpsif_db_tb.g.g.cacode_i.indata[1] top.gpsif_db_tb.g.g.cacode_i.indata[0] 90 | #{top.gpsif_db_tb.g.g.target_i.a[6:0]} top.gpsif_db_tb.g.g.target_i.a[6] top.gpsif_db_tb.g.g.target_i.a[5] top.gpsif_db_tb.g.g.target_i.a[4] top.gpsif_db_tb.g.g.target_i.a[3] top.gpsif_db_tb.g.g.target_i.a[2] top.gpsif_db_tb.g.g.target_i.a[1] top.gpsif_db_tb.g.g.target_i.a[0] 91 | @800022 92 | #{top.gpsif_db_tb.g.g.this_r.sft[0:6]} top.gpsif_db_tb.g.g.this_r.sft[0] top.gpsif_db_tb.g.g.this_r.sft[1] top.gpsif_db_tb.g.g.this_r.sft[2] top.gpsif_db_tb.g.g.this_r.sft[3] top.gpsif_db_tb.g.g.this_r.sft[4] top.gpsif_db_tb.g.g.this_r.sft[5] top.gpsif_db_tb.g.g.this_r.sft[6] 93 | @28 94 | top.gpsif_db_tb.g.g.this_r.sft[0] 95 | top.gpsif_db_tb.g.g.this_r.sft[1] 96 | top.gpsif_db_tb.g.g.this_r.sft[2] 97 | top.gpsif_db_tb.g.g.this_r.sft[3] 98 | top.gpsif_db_tb.g.g.this_r.sft[4] 99 | top.gpsif_db_tb.g.g.this_r.sft[5] 100 | top.gpsif_db_tb.g.g.this_r.sft[6] 101 | #{top.gpsif_db_tb.g.g.cacode_o[2:0]} top.gpsif_db_tb.g.g.cacode_o[2] top.gpsif_db_tb.g.g.cacode_o[1] top.gpsif_db_tb.g.g.cacode_o[0] 102 | @23 103 | #{top.gpsif_db_tb.g.target_o.d[31:0]} top.gpsif_db_tb.g.target_o.d[31] top.gpsif_db_tb.g.target_o.d[30] top.gpsif_db_tb.g.target_o.d[29] top.gpsif_db_tb.g.target_o.d[28] top.gpsif_db_tb.g.target_o.d[27] top.gpsif_db_tb.g.target_o.d[26] top.gpsif_db_tb.g.target_o.d[25] top.gpsif_db_tb.g.target_o.d[24] top.gpsif_db_tb.g.target_o.d[23] top.gpsif_db_tb.g.target_o.d[22] top.gpsif_db_tb.g.target_o.d[21] top.gpsif_db_tb.g.target_o.d[20] top.gpsif_db_tb.g.target_o.d[19] top.gpsif_db_tb.g.target_o.d[18] top.gpsif_db_tb.g.target_o.d[17] top.gpsif_db_tb.g.target_o.d[16] top.gpsif_db_tb.g.target_o.d[15] top.gpsif_db_tb.g.target_o.d[14] top.gpsif_db_tb.g.target_o.d[13] top.gpsif_db_tb.g.target_o.d[12] top.gpsif_db_tb.g.target_o.d[11] top.gpsif_db_tb.g.target_o.d[10] top.gpsif_db_tb.g.target_o.d[9] top.gpsif_db_tb.g.target_o.d[8] top.gpsif_db_tb.g.target_o.d[7] top.gpsif_db_tb.g.target_o.d[6] top.gpsif_db_tb.g.target_o.d[5] top.gpsif_db_tb.g.target_o.d[4] top.gpsif_db_tb.g.target_o.d[3] top.gpsif_db_tb.g.target_o.d[2] top.gpsif_db_tb.g.target_o.d[1] top.gpsif_db_tb.g.target_o.d[0] 104 | @28 105 | top.gpsif_db_tb.g.target_o.ack 106 | @1001200 107 | -group_end 108 | [pattern_trace] 1 109 | [pattern_trace] 0 110 | -------------------------------------------------------------------------------- /tests/gpsif_db_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.std_logic_textio.all; 4 | use ieee.numeric_std.all; 5 | use std.textio.all; 6 | 7 | use work.cpu2j0_pack.all; 8 | use work.test_pkg.all; 9 | use work.bist_pack.all; 10 | use work.gpsif_pack.all; 11 | 12 | entity gpsif_db_tb is 13 | end entity; 14 | 15 | architecture tb of gpsif_db_tb is 16 | signal clk : std_logic := '0'; 17 | signal rst : std_logic := '1'; 18 | shared variable ENDSIM : boolean := false; 19 | 20 | signal dma : dma_req_t; 21 | signal db_i : cpu_data_o_t := NULL_DATA_O; 22 | signal db_o : cpu_data_i_t; 23 | 24 | function read(addr : std_logic_vector(7 downto 0)) 25 | return cpu_data_o_t is 26 | variable r : cpu_data_o_t := NULL_DATA_O; 27 | begin 28 | r.en := '1'; 29 | r.rd := '1'; 30 | r.a := x"00000" & "00" & addr & "00"; 31 | return r; 32 | end; 33 | 34 | function write(addr : std_logic_vector(7 downto 0); 35 | data : std_logic_vector(31 downto 0); 36 | we : std_logic_vector(3 downto 0) := "1111") 37 | return cpu_data_o_t is 38 | variable w : cpu_data_o_t := NULL_DATA_O; 39 | begin 40 | w.en := '1'; 41 | w.wr := '1'; 42 | w.a := x"00000" & "00" & addr & "00"; 43 | w.d := data; 44 | w.we := we; 45 | return w; 46 | end; 47 | 48 | function sign_extend28(x : std_logic_vector(31 downto 0)) 49 | return std_logic_vector is 50 | begin 51 | return x(27) & x(27) & x(27) & x(27) & x(27 downto 0); 52 | end function; 53 | 54 | procedure check_channel( 55 | signal clk : in std_logic; 56 | signal db_i : out cpu_data_o_t; 57 | signal db_o : in cpu_data_i_t; 58 | constant ch : integer; 59 | constant ei : integer; 60 | constant eq : integer; 61 | constant pi : integer; 62 | constant pq : integer; 63 | constant li : integer; 64 | constant lq : integer) is 65 | begin 66 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8 , 8))); 67 | wait until clk = '1' and clk'event and db_o.ack = '1'; 68 | test_equal(to_integer(signed(sign_extend28(db_o.d))), ei, "E_I(" & integer'image(ch) & ")"); 69 | db_i <= NULL_DATA_O; 70 | wait until clk = '1' and clk'event; 71 | 72 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8+1, 8))); 73 | wait until clk = '1' and clk'event and db_o.ack = '1'; 74 | test_equal(to_integer(signed(sign_extend28(db_o.d))), eq, "E_Q(" & integer'image(ch) & ")"); 75 | db_i <= NULL_DATA_O; 76 | wait until clk = '1' and clk'event; 77 | 78 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8+2, 8))); 79 | wait until clk = '1' and clk'event and db_o.ack = '1'; 80 | test_equal(to_integer(signed(sign_extend28(db_o.d))), pi, "P_I(" & integer'image(ch) & ")"); 81 | db_i <= NULL_DATA_O; 82 | wait until clk = '1' and clk'event; 83 | 84 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8+3, 8))); 85 | wait until clk = '1' and clk'event and db_o.ack = '1'; 86 | test_equal(to_integer(signed(sign_extend28(db_o.d))), pq, "P_Q(" & integer'image(ch) & ")"); 87 | db_i <= NULL_DATA_O; 88 | wait until clk = '1' and clk'event; 89 | 90 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8+4, 8))); 91 | wait until clk = '1' and clk'event and db_o.ack = '1'; 92 | test_equal(to_integer(signed(sign_extend28(db_o.d))), li, "L_I(" & integer'image(ch) & ")"); 93 | db_i <= NULL_DATA_O; 94 | wait until clk = '1' and clk'event; 95 | 96 | db_i <= read(std_logic_vector(to_unsigned(16#40#, 8) + to_unsigned(ch*8+5, 8))); 97 | wait until clk = '1' and clk'event and db_o.ack = '1'; 98 | test_equal(to_integer(signed(sign_extend28(db_o.d))), lq, "L_Q(" & integer'image(ch) & ")"); 99 | db_i <= NULL_DATA_O; 100 | wait until clk = '1' and clk'event; 101 | end procedure; 102 | 103 | begin 104 | clk_gen : process 105 | begin 106 | if ENDSIM = false then 107 | clk <= '0'; 108 | wait for 5 ns; 109 | clk <= '1'; 110 | wait for 5 ns; 111 | else 112 | wait; 113 | end if; 114 | end process; 115 | 116 | dma_if_chk : process 117 | variable LI : line; 118 | begin 119 | if ENDSIM = false then 120 | wait until clk = '1' and clk'event; 121 | if dma.req(6) = '1' then 122 | write(LI, "DMA req. of ch #" & integer'image(to_integer(unsigned(dma.req(5 downto 0))))); 123 | writeline(output, LI); 124 | end if; 125 | else 126 | wait; 127 | end if; 128 | end process; 129 | 130 | g : configuration work.gpsif_top_sim 131 | port map ( 132 | clk => clk, 133 | rst => rst, 134 | bi => BIST_SCAN_NOP, 135 | bo => open, 136 | db_i => db_i, 137 | db_o => db_o); 138 | 139 | process 140 | variable write_more : boolean := false; 141 | file FI : TEXT open read_mode is "tests/input.txt"; 142 | variable LI : line; 143 | variable input : std_logic_vector(31 downto 0); 144 | variable data : std_logic_vector(31 downto 0); 145 | variable input_count : integer := 0; 146 | begin 147 | test_plan(36, "gpsif_db_tb"); 148 | wait until clk = '1' and clk'event; 149 | wait until clk = '0' and clk'event; 150 | wait until clk = '1' and clk'event; 151 | wait until clk = '0' and clk'event; 152 | rst <= '0'; 153 | 154 | wait until clk = '1' and clk'event; 155 | wait until clk = '1' and clk'event; 156 | 157 | -- write SFT 158 | db_i <= write(x"00", x"00002ba4"); 159 | wait until clk = '1' and clk'event and db_o.ack = '1'; 160 | db_i <= write(x"01", x"00003182"); 161 | wait until clk = '1' and clk'event and db_o.ack = '1'; 162 | db_i <= write(x"02", x"00002e54"); 163 | wait until clk = '1' and clk'event and db_o.ack = '1'; 164 | db_i <= write(x"03", x"00001640"); 165 | wait until clk = '1' and clk'event and db_o.ack = '1'; 166 | db_i <= write(x"04", x"00002a51"); 167 | wait until clk = '1' and clk'event and db_o.ack = '1'; 168 | db_i <= write(x"05", x"00003097"); 169 | wait until clk = '1' and clk'event and db_o.ack = '1'; 170 | db_i <= NULL_DATA_O; 171 | 172 | -- write g2sft 173 | db_i <= write(x"08", x"00000006"); 174 | wait until clk = '1' and clk'event and db_o.ack = '1'; 175 | db_i <= write(x"09", x"0000041c"); 176 | wait until clk = '1' and clk'event and db_o.ack = '1'; 177 | db_i <= write(x"0a", x"0000080b"); 178 | wait until clk = '1' and clk'event and db_o.ack = '1'; 179 | db_i <= write(x"0b", x"00000c64"); 180 | wait until clk = '1' and clk'event and db_o.ack = '1'; 181 | db_i <= write(x"0c", x"00001200"); 182 | wait until clk = '1' and clk'event and db_o.ack = '1'; 183 | db_i <= write(x"0d", x"000014d2"); 184 | wait until clk = '1' and clk'event and db_o.ack = '1'; 185 | db_i <= NULL_DATA_O; 186 | 187 | -- write PNCO 188 | db_i <= write(x"10", x"00016058"); 189 | wait until clk = '1' and clk'event and db_o.ack = '1'; 190 | db_i <= write(x"11", x"fffe1f88"); 191 | wait until clk = '1' and clk'event and db_o.ack = '1'; 192 | db_i <= write(x"12", x"0000e038"); 193 | wait until clk = '1' and clk'event and db_o.ack = '1'; 194 | db_i <= write(x"13", x"ffff5fd8"); 195 | wait until clk = '1' and clk'event and db_o.ack = '1'; 196 | db_i <= write(x"14", x"fffbbef0"); 197 | wait until clk = '1' and clk'event and db_o.ack = '1'; 198 | db_i <= write(x"15", x"ffffdff8"); 199 | wait until clk = '1' and clk'event and db_o.ack = '1'; 200 | 201 | input_loop: while true loop 202 | -- loop until status register allows input write 203 | write_ready: while true loop 204 | db_i <= read(x"80"); 205 | wait until clk = '1' and clk'event and db_o.ack = '1'; 206 | db_i <= NULL_DATA_O; 207 | data := db_o.d; 208 | if data(0) = '1' then 209 | exit write_ready; 210 | end if; 211 | end loop; 212 | 213 | input := x"00000000"; 214 | for j in 0 to 15 loop -- Read 32b data from 16 lines of 2b data 215 | if endfile(FI) then 216 | exit input_loop; 217 | end if; 218 | readline(FI, LI); 219 | read(LI, input(31 - 2*j downto 30 - 2*j)); 220 | end loop; 221 | 222 | -- Wait for 20 cycles between writing input data to test delays in input 223 | -- arrival 224 | if input_count > 22 then 225 | for i in 1 to 50 loop 226 | wait until clk = '1' and clk'event; 227 | end loop; 228 | else 229 | input_count := input_count + 1; 230 | end if; 231 | 232 | db_i <= write(x"81", input); 233 | wait until clk = '1' and clk'event and db_o.ack = '1'; 234 | db_i <= NULL_DATA_O; 235 | wait until clk = '1' and clk'event; 236 | end loop; 237 | wait until clk = '1' and clk'event; 238 | 239 | -- Check that same values seen in the waveform at the end of the gpsif_tb 240 | check_channel(clk, db_i, db_o, 0, 13270, 7002, 19082, 42342, 21452, 25808); 241 | check_channel(clk, db_i, db_o, 1, 19610, -33416, 28814, -42980, 17464, -26782); 242 | check_channel(clk, db_i, db_o, 2, 31701, -1218, 39655, 2086, 13683, 578); 243 | check_channel(clk, db_i, db_o, 3, 18756, 3118, 33526, 1452, 8116, -17806); 244 | check_channel(clk, db_i, db_o, 4, 41, 16785, -12169, 10099, -9071, 593); 245 | check_channel(clk, db_i, db_o, 5, -2038, -1740, 8074, 23868, -6866, 22632); 246 | -- check_channel(clk, db_i, db_o, 6, -27648, -18944, -18304, -15872, -5120, -7168); 247 | 248 | wait until clk = '1' and clk'event; 249 | wait until clk = '1' and clk'event; 250 | wait until clk = '1' and clk'event; 251 | test_finished("done"); 252 | ENDSIM := true; 253 | wait; 254 | end process; 255 | end architecture; 256 | -------------------------------------------------------------------------------- /tests/gpsif_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.std_logic_textio.all; 4 | use ieee.numeric_std.all; 5 | use std.textio.all; 6 | 7 | use work.cpu2j0_pack.all; 8 | use work.ring_bus_pack.all; 9 | use work.test_pkg.all; 10 | use work.bist_pack.all; 11 | use work.gpsif_pack.all; 12 | use work.gpsif_sub_pack.all; 13 | use work.gpsif_tb_pack.all; 14 | 15 | entity gpsif_tb is 16 | end entity; 17 | 18 | architecture tb of gpsif_tb is 19 | constant clk_tgl : time := 4.0 ns; -- for 125 MHz 20 | -- constant clk_tgl : time := 5.3333 ns; -- for 93.75 MHz 21 | -- constant clk_tgl : time := 5.454 ns; -- for 5.5x gps clk MHz 22 | -- constant clk_tgl : time := 5.714 ns; -- for 87.5 MHz 23 | -- constant clk_tgl : time := 8 ns; -- for 62.5 MHz 24 | -- constant bus_tgl : time := 8.0 ns; -- for 62.5 MHz 25 | constant bus_tgl : time := 4.0 ns; -- for 125 MHz 26 | constant gps_tgl : time := 30.547 ns; -- for 16.368 MHz 27 | constant ppsdds_tgl : time := 30000.0 ns; -- actual 1Hz, accelating test 28 | constant INTERVAL : natural := 4; -- 32b/4cycles = 1Byte/cycle is the maximum input speed for gpsif 29 | constant exe_cycles : natural := 32736; -- running 2ms @16.368Ms/s 30 | constant ANGLE_INI_OLD : boolean := false; 31 | constant GPSIF_NC : natural := 7; 32 | constant ACQ_TEST : boolean := false; 33 | constant SKIP_TEST : boolean := false; 34 | 35 | signal gps_clk : std_logic := '0'; 36 | signal gps_d : std_logic_vector(1 downto 0) := "00"; 37 | signal clk : std_logic := '0'; 38 | signal rst : std_logic := '1'; 39 | signal ppsdds : std_logic := '0'; 40 | signal blgps : blgps_t := NULL_BLGPS; 41 | signal intrpt : std_logic := '0'; 42 | signal bus_clk : std_logic := '0'; 43 | shared variable ENDSIM : boolean := false; 44 | 45 | signal dma : dma_req_t; 46 | signal db_i : cpu_data_o_t := NULL_DATA_O; 47 | signal db_o : cpu_data_i_t; 48 | 49 | begin 50 | clk_gen : process 51 | begin 52 | if ENDSIM = false then 53 | clk <= '1'; wait for clk_tgl; 54 | clk <= '0'; wait for clk_tgl; 55 | else wait; 56 | end if; 57 | end process; 58 | 59 | bus_clk_gen : process 60 | begin 61 | if ENDSIM = false then 62 | bus_clk <= '1'; wait for bus_tgl; 63 | bus_clk <= '0'; wait for bus_tgl; 64 | else wait; 65 | end if; 66 | end process; 67 | 68 | gps_clk_gen : process 69 | begin 70 | if ENDSIM = false then 71 | gps_clk <= '0'; wait for gps_tgl; 72 | gps_clk <= '1'; wait for gps_tgl; 73 | else wait; 74 | end if; 75 | end process; 76 | 77 | ppsdds_gen : process 78 | begin 79 | if ENDSIM = false then 80 | ppsdds <= '0'; wait for ppsdds_tgl; 81 | ppsdds <= '1'; wait for ppsdds_tgl; 82 | else wait; 83 | end if; 84 | end process; 85 | 86 | g : configuration work.gpsif_top_sim 87 | generic map ( GPSIF_NC => GPSIF_NC, 88 | ANGLE_INI_OLD => ANGLE_INI_OLD ) 89 | port map ( 90 | clk => clk, 91 | rst => rst, 92 | gps_clk => gps_clk, 93 | gps_d => gps_d, 94 | ppsdds => ppsdds, 95 | blgps => blgps, 96 | dma => dma, 97 | intrpt => intrpt, 98 | bi => BIST_SCAN_NOP, 99 | bo => open, 100 | ring_i => RBUS_IDLE_9B, 101 | ring_o => open, 102 | bus_clk => bus_clk, 103 | db_i => db_i, 104 | db_o => db_o); 105 | 106 | data_input : process 107 | file FI : TEXT open read_mode is "tests/input.txt"; 108 | variable LI : line; 109 | variable input : std_logic_vector(1 downto 0); 110 | begin 111 | -- gps signal input 112 | input_loop: while true loop 113 | if endfile(FI) then 114 | exit input_loop; 115 | end if; 116 | readline(FI, LI); 117 | read(LI, input(1 downto 0)); 118 | gps_d <= input; 119 | wait until gps_clk = '1' and gps_clk'event; 120 | end loop; 121 | wait; 122 | end process; 123 | 124 | process 125 | file FI : TEXT open read_mode is "tests/input2.txt"; 126 | variable LI : line; 127 | variable input : std_logic_vector(31 downto 0); 128 | variable last : std_logic_vector(31 downto 0) := (others => '0'); 129 | variable sft_chg : integer range 0 to 1023 := 256; 130 | variable sft_ini : integer range 0 to 1023 := 256; 131 | variable set_inc : std_logic_vector(6 downto 0) := (others => '1'); 132 | begin 133 | wait until bus_clk = '1' and bus_clk'event; 134 | wait until bus_clk = '1' and bus_clk'event; 135 | rst <= '0'; 136 | wait until clk = '1' and clk'event; 137 | wait until clk = '1' and clk'event; 138 | 139 | test_plan((GPSIF_NC+6)*6, "gpsif_tb"); 140 | -- write PNCO 141 | -- Values after increment will be for expected values. 142 | db_i <= ('1',x"ABCC0040",'0','1',x"F",x"00006058"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 143 | db_i <= ('1',x"ABCC0044",'0','1',x"F",x"fffd1f88"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 144 | db_i <= ('1',x"ABCC0048",'0','1',x"F",x"ffffe038"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 145 | db_i <= ('1',x"ABCC004c",'0','1',x"F",x"fffe5fd8"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus - minus*4 - inc 146 | db_i <= ('1',x"ABCC0050",'0','1',x"F",x"fffabef0"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 147 | db_i <= ('1',x"ABCC0054",'0','1',x"F",x"fffedff8"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 148 | db_i <= ('1',x"ABCC0058",'0','1',x"F",x"fffedff8"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 149 | db_i <= NULL_DATA_O; 150 | -- write SFT 151 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"00002b98"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 152 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"00007176"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 153 | db_i <= ('1',x"ABCC0008",'0','1',x"F",x"0000ae48"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 154 | db_i <= ('1',x"ABCC000c",'0','1',x"F",x"0000d637"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus - minus*4 - inc 155 | db_i <= ('1',x"ABCC0010",'0','1',x"F",x"00012a45"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 156 | db_i <= ('1',x"ABCC0014",'0','1',x"F",x"00017090"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 157 | db_i <= ('1',x"ABCC0018",'0','1',x"F",x"0001b090"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 158 | db_i <= NULL_DATA_O; 159 | -- write g2sft 160 | db_i <= ('1',x"ABCC0020",'0','1',x"F",x"00000006"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 161 | db_i <= ('1',x"ABCC0024",'0','1',x"F",x"0000001c"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 162 | db_i <= ('1',x"ABCC0028",'0','1',x"F",x"0000000b"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 163 | db_i <= ('1',x"ABCC002c",'0','1',x"F",x"00000064"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 164 | db_i <= ('1',x"ABCC0030",'0','1',x"F",x"00000200"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 165 | db_i <= ('1',x"ABCC0034",'0','1',x"F",x"000000d2"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 166 | db_i <= ('1',x"ABCC0038",'0','1',x"F",x"000000d2"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 167 | db_i <= NULL_DATA_O; 168 | -- correct SFT, increment PNCO 169 | db_i <= ('1',x"ABCC000c",'0','1',x"F",x"c0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus - minus*4 - inc 170 | db_i <= ('1',x"ABCC0014",'0','1',x"F",x"f0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 171 | db_i <= ('1',x"ABCC0018",'0','1',x"F",x"f0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 172 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"bcf00000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 4, 1kHz 173 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"b0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 174 | db_i <= ('1',x"ABCC0008",'0','1',x"F",x"b0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 175 | db_i <= ('1',x"ABCC0010",'0','1',x"F",x"b0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 176 | 177 | for j in 1 to 4 loop 178 | for i in 1 to 17 loop db_i <= NULL_DATA_O; wait until gps_clk = '1' and gps_clk'event; end loop; 179 | wait until bus_clk = '1' and bus_clk'event; -- adjust timing to bus_clk 180 | db_i <= ('1',x"ABCC000c",'0','1',x"F",x"e0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; end loop; -- plus - minus*4 - inc 181 | for i in 1 to 19 loop db_i <= NULL_DATA_O; wait until gps_clk = '1' and gps_clk'event; end loop; 182 | wait until bus_clk = '1' and bus_clk'event; -- adjust timing to bus_clk 183 | db_i <= ('1',x"ABCC000c",'0','1',x"F",x"b0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 184 | db_i <= NULL_DATA_O; 185 | -- Wait for end of execution 186 | for i in 1 to exe_cycles loop wait until gps_clk = '1' and gps_clk'event; chk_dma_req(dma); end loop; 187 | wait until bus_clk = '1' and bus_clk'event; -- adjust timing to bus_clk 188 | -- Check that same values seen in the waveform at the end of the gpsif_tb 189 | if ANGLE_INI_OLD then check_channel(bus_clk, db_o, db_i, 0, 13270, 7002, 19082, 42342, 21452, 25808); 190 | if(GPSIF_NC > 1) then check_channel(bus_clk, db_o, db_i, 1, 19610, -33416, 28814,-42980, 17464,-26782); end if; 191 | if(GPSIF_NC > 2) then check_channel(bus_clk, db_o, db_i, 2, 31701, -1218, 39655, 2086, 13683, 578); end if; 192 | if(GPSIF_NC > 3) then check_channel(bus_clk, db_o, db_i, 3, 18756, 3118, 33526, 1452, 8116,-17806); end if; 193 | if(GPSIF_NC > 4) then check_channel(bus_clk, db_o, db_i, 4, 41, 16785,-12169, 10099, -9071, 593); end if; 194 | if(GPSIF_NC > 5) then check_channel(bus_clk, db_o, db_i, 5, -2038, -1740, 8074, 23868, -6866, 22632); end if; 195 | if(GPSIF_NC > 6) then check_channel(bus_clk, db_o, db_i, 6, -2038, -1740, 8074, 23868, -6866, 22632); end if; 196 | else check_channel(bus_clk, db_o, db_i, 0, -7067, 13225,-42327, 19061,-25709, 21447); 197 | if(GPSIF_NC > 1) then check_channel(bus_clk, db_o, db_i, 1, 33477, 19603, 43079, 28829, 26827, 17517); end if; 198 | if(GPSIF_NC > 2) then check_channel(bus_clk, db_o, db_i, 2, 1206, 31727, -2054, 39687, -562, 13701); end if; 199 | if(GPSIF_NC > 3) then check_channel(bus_clk, db_o, db_i, 3, -3137, 18763, -1443, 33571, 17805, 8119); end if; 200 | if(GPSIF_NC > 4) then check_channel(bus_clk, db_o, db_i, 4,-16875, 59,-10147,-12217, -477, -9121); end if; 201 | if(GPSIF_NC > 5) then check_channel(bus_clk, db_o, db_i, 5, 1743, -2041,-23865, 8079,-22653, -6869); end if; 202 | if(GPSIF_NC > 6) then check_channel(bus_clk, db_o, db_i, 6, 1743, -2041,-23865, 8079,-22653, -6869); end if; end if; 203 | wait until bus_clk = '1' and bus_clk'event; 204 | wait until bus_clk = '1' and bus_clk'event; 205 | 206 | -- Reset to test the mode of CPU bus input 207 | db_i <= ('1',x"ABCC0060",'0','1',x"F",x"00000001"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 208 | -- write PNCO 209 | db_i <= ('1',x"ABCC0040",'0','1',x"F",x"00006058"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus 210 | db_i <= ('1',x"ABCC0044",'0','1',x"F",x"fffd1f88"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 211 | db_i <= ('1',x"ABCC0048",'0','1',x"F",x"0000e038"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 212 | db_i <= ('1',x"ABCC004c",'0','1',x"F",x"ffff5fd8"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 213 | db_i <= ('1',x"ABCC0050",'0','1',x"F",x"fffbbef0"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 214 | db_i <= ('1',x"ABCC0054",'0','1',x"F",x"ffffdff8"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 215 | db_i <= NULL_DATA_O; 216 | -- write SFT 217 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"00000007"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus 218 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"00000011"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 219 | db_i <= ('1',x"ABCC0008",'0','1',x"F",x"0000ae4c"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 220 | db_i <= ('1',x"ABCC000c",'0','1',x"F",x"0000d638"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 221 | db_i <= ('1',x"ABCC0010",'0','1',x"F",x"00012a49"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 222 | db_i <= ('1',x"ABCC0014",'0','1',x"F",x"0001708f"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 223 | db_i <= NULL_DATA_O; 224 | -- write g2sft 225 | db_i <= ('1',x"ABCC0020",'0','1',x"F",x"00000006"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus - minus 226 | db_i <= ('1',x"ABCC0024",'0','1',x"F",x"0000001c"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus - plus 227 | db_i <= ('1',x"ABCC0028",'0','1',x"F",x"0000000b"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 228 | db_i <= ('1',x"ABCC002c",'0','1',x"F",x"00000064"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 229 | db_i <= ('1',x"ABCC0030",'0','1',x"F",x"00000200"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 230 | db_i <= ('1',x"ABCC0034",'0','1',x"F",x"000000d2"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 231 | db_i <= NULL_DATA_O; 232 | input_loop: while true loop 233 | input := x"00000000"; 234 | for j in 0 to 15 loop -- Read 32b data from 16 lines of 2b data 235 | if endfile(FI) then 236 | exit input_loop; 237 | end if; 238 | readline(FI, LI); 239 | read(LI, input(31 - 2*j downto 30 - 2*j)); 240 | end loop; 241 | db_i <= ('1',x"ABCC0204",'0','1',x"F",input); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; chk_dma_req(dma); 242 | -- loop until status register allows input write 243 | write_ready: while true loop 244 | db_i <= ('1',x"ABCC0200",'1','0',x"F",x"00000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; chk_dma_req(dma); 245 | db_i <= NULL_DATA_O; 246 | if db_o.d(0) = '1' then 247 | exit write_ready; 248 | elsif sft_chg > 0 then 249 | sft_chg := sft_chg -1; 250 | if sft_chg = 128 then 251 | -- SFT +- 1 252 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"c0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus 253 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"e0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 254 | db_i <= NULL_DATA_O; 255 | elsif sft_chg = 0 then 256 | -- SFT -+ 1 257 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"e0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- minus 258 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"c0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- plus 259 | db_i <= NULL_DATA_O; 260 | end if; 261 | elsif sft_ini > 0 then 262 | sft_ini := sft_ini -1; 263 | if sft_ini = 0 then 264 | -- write SFT 265 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"00002b8c"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 266 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"0000716a"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 267 | db_i <= ('1',x"ABCC0000",'0','1',x"F",x"baf00000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 16, inc 1kHz 268 | db_i <= ('1',x"ABCC0004",'0','1',x"F",x"b0000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- inc 16, inc 1kHz 269 | db_i <= ('1',x"ABCC0020",'0','1',x"F",x"00000006"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- reset C/A code 270 | db_i <= ('1',x"ABCC0024",'0','1',x"F",x"0000001c"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; -- reset C/A code 271 | db_i <= NULL_DATA_O; 272 | end if; 273 | end if; 274 | end loop; 275 | for j in 1 to INTERVAL-2 loop 276 | wait until bus_clk = '1' and bus_clk'event; chk_dma_req(dma); 277 | end loop; 278 | end loop; 279 | -- Check that same values seen in the waveform at the end of the gpsif_tb 280 | if ANGLE_INI_OLD then check_channel(bus_clk, db_o, db_i, 0, 13270, 7002, 19082, 42342, 21452, 25808); 281 | if(GPSIF_NC > 1) then check_channel(bus_clk, db_o, db_i, 1, 19610, -33416, 28814,-42980, 17464,-26782); end if; 282 | if(GPSIF_NC > 2) then check_channel(bus_clk, db_o, db_i, 2, 31701, -1218, 39655, 2086, 13683, 578); end if; 283 | if(GPSIF_NC > 3) then check_channel(bus_clk, db_o, db_i, 3, 18756, 3118, 33526, 1452, 8116,-17806); end if; 284 | if(GPSIF_NC > 4) then check_channel(bus_clk, db_o, db_i, 4, 41, 16785,-12169, 10099, -9071, 593); end if; 285 | if(GPSIF_NC > 5) then check_channel(bus_clk, db_o, db_i, 5, -2038, -1740, 8074, 23868, -6866, 22632); end if; 286 | else check_channel(bus_clk, db_o, db_i, 0, -7067, 13225,-42327, 19061,-25709, 21447); 287 | if(GPSIF_NC > 1) then check_channel(bus_clk, db_o, db_i, 1, 33477, 19603, 43079, 28829, 26827, 17517); end if; 288 | if(GPSIF_NC > 2) then check_channel(bus_clk, db_o, db_i, 2, 1206, 31727, -2054, 39687, -562, 13701); end if; 289 | if(GPSIF_NC > 3) then check_channel(bus_clk, db_o, db_i, 3, -3137, 18763, -1443, 33571, 17805, 8119); end if; 290 | if(GPSIF_NC > 4) then check_channel(bus_clk, db_o, db_i, 4,-16875, 59,-10147,-12217, -477, -9121); end if; 291 | if(GPSIF_NC > 5) then check_channel(bus_clk, db_o, db_i, 5, 1743, -2041,-23865, 8079,-22653, -6869); end if; end if; 292 | 293 | -- dump signals 294 | for i in 1 to 256 loop 295 | db_i <= ('1',x"ABCC0080",'1','0',x"F",x"00000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 296 | db_i <= ('1',x"ABCC00a0",'1','0',x"F",x"00000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 297 | db_i <= ('1',x"ABCC00c0",'1','0',x"F",x"00000000"); wait until bus_clk = '1' and bus_clk'event and db_o.ack = '1'; 298 | end loop; 299 | db_i <= NULL_DATA_O; 300 | 301 | test_finished("done"); 302 | ENDSIM := true; 303 | wait; 304 | end process; 305 | 306 | end architecture; 307 | -------------------------------------------------------------------------------- /tests/gpsif_tb_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.std_logic_textio.all; 4 | use ieee.std_logic_unsigned.all; 5 | use ieee.numeric_std.all; 6 | use std.textio.all; 7 | 8 | use work.cpu2j0_pack.all; 9 | use work.gpsif_pack.all; 10 | use work.gpsif_sub_pack.all; 11 | use work.test_pkg.all; 12 | 13 | package gpsif_tb_pack is 14 | procedure chk_dma_req(dma : dma_req_t); 15 | procedure check_equal( 16 | signal clk : in std_logic; 17 | signal db_o : in cpu_data_i_t; 18 | signal db_i : out cpu_data_o_t; 19 | constant val,ch,ofs : integer; 20 | constant typ : string); 21 | procedure check_channel( 22 | signal clk : in std_logic; 23 | signal db_o : in cpu_data_i_t; 24 | signal db_i : out cpu_data_o_t; 25 | constant ch,ei,eq,pi,pq,li,lq : integer); 26 | end package; 27 | 28 | package body gpsif_tb_pack is 29 | 30 | procedure chk_dma_req(dma : dma_req_t) is 31 | variable LI : line; 32 | begin 33 | if dma.req(6) = '1' then 34 | write(LI, "DMA req. of ch #" & integer'image(to_integer(unsigned(dma.req(5 downto 0))))); 35 | writeline(output, LI); 36 | end if; 37 | end procedure; 38 | 39 | procedure check_equal( 40 | signal clk : in std_logic; 41 | signal db_o : in cpu_data_i_t; 42 | signal db_i : out cpu_data_o_t; 43 | constant val,ch,ofs : integer; 44 | constant typ : string) is 45 | begin 46 | db_i <= ('1',(std_logic_vector(to_unsigned(ch*8 + ofs,30)) & "00") or x"ABCC0100",'1','0',x"F",x"00000000"); 47 | wait until clk = '1' and clk'event and db_o.ack = '1'; 48 | test_equal(to_integer(signed(db_o.d)),val, typ & "(" & integer'image(ch) & ")"); 49 | end procedure; 50 | 51 | procedure check_channel( 52 | signal clk : in std_logic; 53 | signal db_o : in cpu_data_i_t; 54 | signal db_i : out cpu_data_o_t; 55 | constant ch,ei,eq,pi,pq,li,lq : integer) is 56 | begin 57 | check_equal(clk,db_o,db_i,ei,ch,0,"E_I"); 58 | check_equal(clk,db_o,db_i,eq,ch,1,"E_Q"); 59 | check_equal(clk,db_o,db_i,pi,ch,2,"P_I"); 60 | check_equal(clk,db_o,db_i,pq,ch,3,"P_Q"); 61 | check_equal(clk,db_o,db_i,li,ch,4,"L_I"); 62 | check_equal(clk,db_o,db_i,lq,ch,5,"L_Q"); 63 | db_i <= NULL_DATA_O; wait until clk = '1' and clk'event; 64 | end procedure; 65 | 66 | end gpsif_tb_pack; 67 | -------------------------------------------------------------------------------- /tests/gpsob/Makefile_gpsob: -------------------------------------------------------------------------------- 1 | VHDLS := VHDS 2 | include build.mk 3 | 4 | VHDS += tests/gpsob/gpsif_tb_gpsob.vhd 5 | VHDS += tests/gpsif_tb_pkg.vhd 6 | VHDS += tools/tests/tap/test_pkg.vhd 7 | 8 | VHDL_TESTS := gpsif_tb_gpsob 9 | 10 | # if gpsif repo is inside the soc_top repo, pull in other vhdl files 11 | # and build gpsif_tb 12 | MK_UTILS := $(wildcard ../../tools/mk_utils.mk) 13 | ifeq ($(MK_UTILS),) 14 | MK_UTILS := $(wildcard ../tools/mk_utils.mk) 15 | include $(MK_UTILS) 16 | VHDS += $(call include_vhdl,../lib/reg_file_struct) 17 | endif 18 | MK_UTILS := $(wildcard ../../tools/mk_utils.mk) 19 | ifneq ($(MK_UTILS),) 20 | include $(MK_UTILS) 21 | VHDS += $(call include_vhdl,../cpu) 22 | VHDS += $(call include_vhdl,../ring_bus) 23 | VHDS += $(call include_vhdl,../../lib/fixed_dsm_pkg) 24 | VHDS += $(call include_vhdl,../../lib/reg_file_struct) 25 | VHDS += $(call include_vhdl,../../lib/memory_tech_lib) 26 | VHDS += $(call include_vhdl,../../lib/hwutils) 27 | endif 28 | 29 | VHDL_TOPS += $(VHDL_TESTS) 30 | 31 | TOOLS_DIR := $(firstword $(wildcard ../../tools) tools) 32 | 33 | all: $(VHDL_TOPS) 34 | 35 | work-obj93.cf: $(VHDS) 36 | 37 | tests/gpsif_tb_gpsob.ghw: gpsif_tb_gpsob 38 | ./gpsif_tb_gpsob --wave=$@ --stop-time=2500us --ieee-asserts=disable 39 | 40 | RUNTESTS := $(TOOLS_DIR)/tests/runtests 41 | $(RUNTESTS): 42 | make -C $(dir $@) 43 | 44 | check: $(RUNTESTS) $(VHDL_TESTS) 45 | $(RUNTESTS) test_bins 46 | 47 | tap: $(RUNTESTS) $(VHDL_TESTS) 48 | $(RUNTESTS) -t test_bins 49 | 50 | include $(TOOLS_DIR)/ghdl.mk 51 | 52 | clean: 53 | rm -f *.cf *.o $(VHDL_TOPS) *_tap tests/*.ghw 54 | rm -f gpsif.vhd gpsif_reg.vhd cacode.vhd gpsif_db.vhd gpsif_buf.vhd rbus_adp.vhd 55 | make -C $(dir $(RUNTESTS)) clean 56 | 57 | .PHONY: all clean check tap 58 | -------------------------------------------------------------------------------- /tests/gpsob/README: -------------------------------------------------------------------------------- 1 | READMEs 2 | for gps over bitlilnk RTL simulation 3 | 4 | # -- vector data creation 5 | cat input.txt input.txt > input3.txt 6 | 7 | # -- run simulation 8 | make -f tests/gpsob/Makefile_gpsob tests/gpsif_tb_gpsob.ghw 9 | (Makefile_gpsob specifies, 2500us) 10 | 11 | # -- pass judgement method (automatic compare is not coded) 12 | diff acm_bank set value of gpsif_tb.vhd (1ms - 2ms, set once) 13 | and 14 | acm_bank set value of gpsif_tb_gpsob.vhd (1ms - 2ms, set once) 15 | (2 bit sample) 16 | 17 | # -- pass judgement method (automatic compare is not coded) 18 | diff acm_bank set value of gpsif_tb.vhd (1ms - 2ms, set once) 19 | (here, modifiy input.txt to simulate 1 bit sample) 20 | and 21 | acm_bank set value of gpsif_tb_gpsob.vhd (1ms - 2ms, set once) 22 | (1 bit sample) 23 | 24 | -------------------------------------------------------------------------------- /tests/output.golden: -------------------------------------------------------------------------------- 1 | RTL scilab(スケール) 2 | ch 0 E I 13270 13823.2636 3 | ch 0 E Q 7002 6369.74055 4 | ch 0 P I 19082 21596.543 5 | ch 0 P Q 42342 41015.6471 6 | ch 0 L I 21452 22581.9309 7 | ch 0 L Q 25808 24266.027 8 | 9 | ch 1 E I 19610 17864.0066 10 | ch 1 E Q -33416 -33986.9417 11 | ch 1 P I 28814 25953.9501 12 | ch 1 P Q -42980 -43525.8691 13 | ch 1 L I 17464 15713.9891 14 | ch 1 L Q -26782 -27500.4761 15 | 16 | ch 2 E I 31701 31199.4215 17 | ch 2 E Q -1218 -2660.5226 18 | ch 2 P I 39655 39390.571 19 | ch 2 P Q 2086 61.201696 20 | ch 2 L I 13683 13859.681 21 | ch 2 L Q 578 -404.860315 22 | 23 | ch 3 E I 18756 18320.9667 24 | ch 3 E Q 3118 2153.91711 25 | ch 3 P I 33526 33077.2592 26 | ch 3 P Q 1452 -313.385172 27 | ch 3 L I 8116 6667.05973 28 | ch 3 L Q -17806 -17659.9623 29 | 30 | ch 4 E I 41 1130.54181 31 | ch 4 E Q 16785 16447.2867 32 | ch 4 P I -12169 -11400.356 33 | ch 4 P Q 10099 10471.0422 34 | ch 4 L I -9071 -8735.83329 35 | ch 4 L Q 593 902.019975 36 | 37 | ch 5 E I -2038 -2132.58843 38 | ch 5 E Q -1740 -2110.0271 39 | ch 5 P I 8074 8891.66381 40 | ch 5 P Q 23868 23018.9347 41 | ch 5 L I -6866 -5457.77001 42 | ch 5 L Q 22632 22822.634 43 | -------------------------------------------------------------------------------- /tools/common.mk: -------------------------------------------------------------------------------- 1 | # find v2p in directory this file is in 2 | V2P := $(dir $(lastword $(MAKEFILE_LIST)))v2p 3 | 4 | # depend on force to always convert files but convert to *.temp and 5 | # then use cmp || mv to avoid needlessly updating the timestamp and 6 | # causing unwanted rebuilds 7 | 8 | # override LD_LIBRARY_PATH when running v2p to avoid Xilinx's libraries 9 | # causing errors like this: 10 | # /usr/lib/gcc/i586-suse-linux/4.5/cc1: /opt/Xilinx/13.1/ISE_DS/common/lib/lin/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by /usr/lib/libppl_c.so.2) 11 | 12 | %.vhd: %.vhm force 13 | $(info Convert $< -> $@) 14 | @LD_LIBRARY_PATH='' perl $(V2P) < $< > $@.temp 15 | @cmp -s $@.temp $@ || mv $@.temp $@ 16 | @rm -f $@.temp 17 | 18 | # vhmh lets us run a file through the preprocessor before v2p 19 | %.vhm: %.vhmh force 20 | $(info Convert $< -> $@) 21 | @LD_LIBRARY_PATH='' gcc -x c-header -E -P -w -nostdinc -I. -Iconfig $< -o $@.temp 22 | @cmp -s $@.temp $@ || mv $@.temp $@ 23 | @rm -f $@.temp 24 | 25 | %.vhh: %.vhd force 26 | $(info Convert $< -> $@) 27 | @LD_LIBRARY_PATH='' gcc -x c-header -E -P -w -nostdinc -I. -Iconfig $< -o $@.temp 28 | @cmp -s $@.temp $@ || mv $@.temp $@ 29 | @rm -f $@.temp 30 | 31 | .PHONY: force 32 | -------------------------------------------------------------------------------- /tools/ghdl.mk: -------------------------------------------------------------------------------- 1 | # This is a makefile snippet useful for simulating with ghdl on both 2 | # Linux and OSX. On both platforms it will create a create an 3 | # executable file that can be used to run the simulation. 4 | 5 | # To use this, set VHDL_TOPS and optionally VHDL_LIBS (described 6 | # below), define the dependicies between the vhdl library file and vhd 7 | # files it will contain, and include this file. 8 | 9 | # For example: 10 | # 11 | # VHDL_TOPS := foo 12 | # work-obj93.cf: foo.vhd foo_pkg.vhd 13 | # include tools/ghdl.mk 14 | # 15 | # Variables that can be set to modify this files behaviour: 16 | # VHDL_TOPS = names of top entities that will be simulated 17 | # VHDL_LIBS = names of VHDL libraries. Defaults to "work" 18 | 19 | ifeq ($(VHDL_TOPS),) 20 | $(error Need to set VHDL_TOPS) 21 | endif 22 | 23 | include $(dir $(lastword $(MAKEFILE_LIST)))common.mk 24 | 25 | VHDL_LIBS ?= work 26 | VHDL_LIBS := $(addsuffix -obj93.cf,$(VHDL_LIBS)) 27 | 28 | GHDL ?= ghdl 29 | GHDL_EXISTS := $(shell sh -c 'which $(GHDL) >/dev/null && echo true') 30 | 31 | ifeq ($(GHDL_EXISTS),true) 32 | %-obj93.cf: 33 | $(GHDL) -i --work=$* $(filter %.vhh %.vhd %.vhdl,$^) 34 | 35 | # look at ghdl --version output to determine backend generator type 36 | define check_backend 37 | (ghdl --version 2> /dev/null | grep -i "$(1).*generator" -q) && echo y 38 | endef 39 | 40 | GHDL_BACKEND_GCC := $(shell $(call check_backend,gcc)) 41 | GHDL_BACKEND_LLVM := $(shell $(call check_backend,llvm)) 42 | GHDL_BACKEND_MCODE := $(shell $(call check_backend,mcode)) 43 | 44 | ifeq ($(GHDL_BACKEND_GCC)$(GHDL_BACKEND_LLVM),y) 45 | # for compiler backends, use -m to compile binaries for each top 46 | $(VHDL_TOPS): $(VHDL_LIBS) 47 | $(GHDL) -m -fexplicit --ieee=synopsys $@ 48 | else 49 | ifeq ($(GHDL_BACKEND_MCODE),y) 50 | # With an mcode backend, create wrapper scripts that compile and run 51 | # the test benches 52 | $(VHDL_TOPS): $(VHDL_LIBS) 53 | echo "#!/bin/sh" > $@ 54 | echo 'ghdl -c -fexplicit --ieee=synopsys -r $@ $$@' >> $@ 55 | chmod +x $@ 56 | else 57 | $(error Unrecognized GHDL backend) 58 | endif 59 | endif 60 | 61 | endif 62 | 63 | #clean:: 64 | # -$(GHDL) --remove 65 | # rm -f *.lst 66 | -------------------------------------------------------------------------------- /tools/tests/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS += -Wall 3 | 4 | runtests: runtests.o 5 | 6 | clean: 7 | rm -f runtests *.o 8 | -------------------------------------------------------------------------------- /tools/tests/tap/basic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Some utility routines for writing tests. 3 | * 4 | * Here are a variety of utility routines for writing tests compatible with 5 | * the TAP protocol. All routines of the form ok() or is*() take a test 6 | * number and some number of appropriate arguments, check to be sure the 7 | * results match the expected output using the arguments, and print out 8 | * something appropriate for that test number. Other utility routines help in 9 | * constructing more complex tests, skipping tests, reporting errors, setting 10 | * up the TAP output format, or finding things in the test environment. 11 | * 12 | * This file is part of C TAP Harness. The current version plus supporting 13 | * documentation is at . 14 | * 15 | * Copyright 2009, 2010, 2011, 2012 Russ Allbery 16 | * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 17 | * The Board of Trustees of the Leland Stanford Junior University 18 | * 19 | * Permission is hereby granted, free of charge, to any person obtaining a 20 | * copy of this software and associated documentation files (the "Software"), 21 | * to deal in the Software without restriction, including without limitation 22 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 23 | * and/or sell copies of the Software, and to permit persons to whom the 24 | * Software is furnished to do so, subject to the following conditions: 25 | * 26 | * The above copyright notice and this permission notice shall be included in 27 | * all copies or substantial portions of the Software. 28 | * 29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 32 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 34 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 35 | * DEALINGS IN THE SOFTWARE. 36 | */ 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #ifdef _WIN32 44 | # include 45 | #else 46 | # include 47 | #endif 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | 54 | /* Windows provides mkdir and rmdir under different names. */ 55 | #ifdef _WIN32 56 | # define mkdir(p, m) _mkdir(p) 57 | # define rmdir(p) _rmdir(p) 58 | #endif 59 | 60 | /* 61 | * The test count. Always contains the number that will be used for the next 62 | * test status. 63 | */ 64 | unsigned long testnum = 1; 65 | 66 | /* 67 | * Status information stored so that we can give a test summary at the end of 68 | * the test case. We store the planned final test and the count of failures. 69 | * We can get the highest test count from testnum. 70 | * 71 | * We also store the PID of the process that called plan() and only summarize 72 | * results when that process exits, so as to not misreport results in forked 73 | * processes. 74 | * 75 | * If _lazy is true, we're doing lazy planning and will print out the plan 76 | * based on the last test number at the end of testing. 77 | */ 78 | static unsigned long _planned = 0; 79 | static unsigned long _failed = 0; 80 | static pid_t _process = 0; 81 | static int _lazy = 0; 82 | 83 | static FILE *output;; 84 | 85 | /* 86 | * Our exit handler. Called on completion of the test to report a summary of 87 | * results provided we're still in the original process. This also handles 88 | * printing out the plan if we used plan_lazy(), although that's suppressed if 89 | * we never ran a test (due to an early bail, for example). 90 | */ 91 | static void 92 | finish(void) 93 | { 94 | unsigned long highest = testnum - 1; 95 | 96 | if (_planned == 0 && !_lazy) 97 | return; 98 | fflush(stderr); 99 | if (_process != 0 && getpid() == _process) { 100 | if (_lazy && highest > 0) { 101 | fprintf(output, "1..%lu\n", highest); 102 | _planned = highest; 103 | } 104 | if (_planned > highest) 105 | fprintf(output, "# Looks like you planned %lu test%s but only ran %lu\n", 106 | _planned, (_planned > 1 ? "s" : ""), highest); 107 | else if (_planned < highest) 108 | fprintf(output, "# Looks like you planned %lu test%s but ran %lu extra\n", 109 | _planned, (_planned > 1 ? "s" : ""), highest - _planned); 110 | else if (_failed > 0) 111 | fprintf(output, "# Looks like you failed %lu test%s of %lu\n", _failed, 112 | (_failed > 1 ? "s" : ""), _planned); 113 | else if (_planned > 1) 114 | fprintf(output, "# All %lu tests successful or skipped\n", _planned); 115 | else 116 | fprintf(output, "# %lu test successful or skipped\n", _planned); 117 | } 118 | } 119 | 120 | static void init_tap_file(void) { 121 | output = stdout; 122 | char *tap_path = getenv("TAP_FILE"); 123 | if (tap_path) { 124 | output = fopen(tap_path, "w"); 125 | if (output == 0) { 126 | fprintf(stderr, "# cannot open TAP file \"%s\" for writting: %s\n", 127 | tap_path, strerror(errno)); 128 | exit(1); 129 | } 130 | } 131 | } 132 | 133 | /* 134 | * Initialize things. Turns on line buffering on stdout and then prints out 135 | * the number of tests in the test suite. 136 | */ 137 | void 138 | plan(unsigned long count) 139 | { 140 | init_tap_file(); 141 | if (setvbuf(output, NULL, _IOLBF, BUFSIZ) != 0) 142 | fprintf(stderr, "# cannot set output to line buffered: %s\n", 143 | strerror(errno)); 144 | fflush(stderr); 145 | fprintf(output, "1..%lu\n", count); 146 | testnum = 1; 147 | _planned = count; 148 | _process = getpid(); 149 | atexit(finish); 150 | } 151 | 152 | 153 | /* 154 | * Initialize things for lazy planning, where we'll automatically print out a 155 | * plan at the end of the program. Turns on line buffering on stdout as well. 156 | */ 157 | void 158 | plan_lazy(void) 159 | { 160 | init_tap_file(); 161 | if (setvbuf(output, NULL, _IOLBF, BUFSIZ) != 0) 162 | fprintf(stderr, "# cannot set output to line buffered: %s\n", 163 | strerror(errno)); 164 | testnum = 1; 165 | _process = getpid(); 166 | _lazy = 1; 167 | atexit(finish); 168 | } 169 | 170 | 171 | /* 172 | * Skip the entire test suite and exits. Should be called instead of plan(), 173 | * not after it, since it prints out a special plan line. 174 | */ 175 | void 176 | skip_all(const char *format, ...) 177 | { 178 | fflush(stderr); 179 | fprintf(output, "1..0 # skip"); 180 | if (format != NULL) { 181 | va_list args; 182 | 183 | putchar(' '); 184 | va_start(args, format); 185 | vfprintf(output, format, args); 186 | va_end(args); 187 | } 188 | putchar('\n'); 189 | exit(0); 190 | } 191 | 192 | 193 | /* 194 | * Print the test description. 195 | */ 196 | static void 197 | print_desc(const char *format, va_list args) 198 | { 199 | fprintf(output, " - "); 200 | vfprintf(output, format, args); 201 | } 202 | 203 | 204 | /* 205 | * Takes a boolean success value and assumes the test passes if that value 206 | * is true and fails if that value is false. 207 | */ 208 | void 209 | ok(int success, const char *format, ...) 210 | { 211 | fflush(stderr); 212 | fprintf(output, "%sok %lu", success ? "" : "not ", testnum++); 213 | if (!success) 214 | _failed++; 215 | if (format != NULL) { 216 | va_list args; 217 | 218 | va_start(args, format); 219 | print_desc(format, args); 220 | va_end(args); 221 | } 222 | putchar('\n'); 223 | } 224 | 225 | 226 | /* 227 | * Same as ok(), but takes the format arguments as a va_list. 228 | */ 229 | void 230 | okv(int success, const char *format, va_list args) 231 | { 232 | fflush(stderr); 233 | fprintf(output, "%sok %lu", success ? "" : "not ", testnum++); 234 | if (!success) 235 | _failed++; 236 | if (format != NULL) 237 | print_desc(format, args); 238 | putchar('\n'); 239 | } 240 | 241 | 242 | /* 243 | * Skip a test. 244 | */ 245 | void 246 | skip(const char *reason, ...) 247 | { 248 | fflush(stderr); 249 | fprintf(output, "ok %lu # skip", testnum++); 250 | if (reason != NULL) { 251 | va_list args; 252 | 253 | va_start(args, reason); 254 | putchar(' '); 255 | vfprintf(output, reason, args); 256 | va_end(args); 257 | } 258 | putchar('\n'); 259 | } 260 | 261 | 262 | /* 263 | * Report the same status on the next count tests. 264 | */ 265 | void 266 | ok_block(unsigned long count, int status, const char *format, ...) 267 | { 268 | unsigned long i; 269 | 270 | fflush(stderr); 271 | for (i = 0; i < count; i++) { 272 | fprintf(output, "%sok %lu", status ? "" : "not ", testnum++); 273 | if (!status) 274 | _failed++; 275 | if (format != NULL) { 276 | va_list args; 277 | 278 | va_start(args, format); 279 | print_desc(format, args); 280 | va_end(args); 281 | } 282 | putchar('\n'); 283 | } 284 | } 285 | 286 | 287 | /* 288 | * Skip the next count tests. 289 | */ 290 | void 291 | skip_block(unsigned long count, const char *reason, ...) 292 | { 293 | unsigned long i; 294 | 295 | fflush(stderr); 296 | for (i = 0; i < count; i++) { 297 | fprintf(output, "ok %lu # skip", testnum++); 298 | if (reason != NULL) { 299 | va_list args; 300 | 301 | va_start(args, reason); 302 | putchar(' '); 303 | vfprintf(output, reason, args); 304 | va_end(args); 305 | } 306 | putchar('\n'); 307 | } 308 | } 309 | 310 | 311 | /* 312 | * Takes an expected integer and a seen integer and assumes the test passes 313 | * if those two numbers match. 314 | */ 315 | void 316 | is_int(long wanted, long seen, const char *format, ...) 317 | { 318 | fflush(stderr); 319 | if (wanted == seen) 320 | fprintf(output, "ok %lu", testnum++); 321 | else { 322 | fprintf(output, "# wanted: %ld\n# seen: %ld\n", wanted, seen); 323 | fprintf(output, "not ok %lu", testnum++); 324 | _failed++; 325 | } 326 | if (format != NULL) { 327 | va_list args; 328 | 329 | va_start(args, format); 330 | print_desc(format, args); 331 | va_end(args); 332 | } 333 | putchar('\n'); 334 | } 335 | 336 | 337 | /* 338 | * Takes a string and what the string should be, and assumes the test passes 339 | * if those strings match (using strcmp). 340 | */ 341 | void 342 | is_string(const char *wanted, const char *seen, const char *format, ...) 343 | { 344 | if (wanted == NULL) 345 | wanted = "(null)"; 346 | if (seen == NULL) 347 | seen = "(null)"; 348 | fflush(stderr); 349 | if (strcmp(wanted, seen) == 0) 350 | fprintf(output, "ok %lu", testnum++); 351 | else { 352 | fprintf(output, "# wanted: %s\n# seen: %s\n", wanted, seen); 353 | fprintf(output, "not ok %lu", testnum++); 354 | _failed++; 355 | } 356 | if (format != NULL) { 357 | va_list args; 358 | 359 | va_start(args, format); 360 | print_desc(format, args); 361 | va_end(args); 362 | } 363 | putchar('\n'); 364 | } 365 | 366 | 367 | /* 368 | * Takes an expected unsigned long and a seen unsigned long and assumes the 369 | * test passes if the two numbers match. Otherwise, reports them in hex. 370 | */ 371 | void 372 | is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) 373 | { 374 | fflush(stderr); 375 | if (wanted == seen) 376 | fprintf(output, "ok %lu", testnum++); 377 | else { 378 | fprintf(output, "# wanted: %lx\n# seen: %lx\n", (unsigned long) wanted, 379 | (unsigned long) seen); 380 | fprintf(output, "not ok %lu", testnum++); 381 | _failed++; 382 | } 383 | if (format != NULL) { 384 | va_list args; 385 | 386 | va_start(args, format); 387 | print_desc(format, args); 388 | va_end(args); 389 | } 390 | putchar('\n'); 391 | } 392 | 393 | 394 | /* 395 | * Bail out with an error. 396 | */ 397 | void 398 | bail(const char *format, ...) 399 | { 400 | va_list args; 401 | 402 | fflush(stderr); 403 | fflush(output); 404 | fprintf(output, "Bail out! "); 405 | va_start(args, format); 406 | vfprintf(output, format, args); 407 | va_end(args); 408 | fprintf(output, "\n"); 409 | exit(1); 410 | } 411 | 412 | 413 | /* 414 | * Bail out with an error, appending strerror(errno). 415 | */ 416 | void 417 | sysbail(const char *format, ...) 418 | { 419 | va_list args; 420 | int oerrno = errno; 421 | 422 | fflush(stderr); 423 | fflush(output); 424 | fprintf(output, "Bail out! "); 425 | va_start(args, format); 426 | vfprintf(output, format, args); 427 | va_end(args); 428 | fprintf(output, ": %s\n", strerror(oerrno)); 429 | exit(1); 430 | } 431 | 432 | 433 | /* 434 | * Report a diagnostic to stderr. 435 | */ 436 | void 437 | diag(const char *format, ...) 438 | { 439 | va_list args; 440 | 441 | fflush(stderr); 442 | fflush(output); 443 | fprintf(output, "# "); 444 | va_start(args, format); 445 | vfprintf(output, format, args); 446 | va_end(args); 447 | fprintf(output, "\n"); 448 | } 449 | 450 | 451 | /* 452 | * Report a diagnostic to stderr, appending strerror(errno). 453 | */ 454 | void 455 | sysdiag(const char *format, ...) 456 | { 457 | va_list args; 458 | int oerrno = errno; 459 | 460 | fflush(stderr); 461 | fflush(output); 462 | fprintf(output, "# "); 463 | va_start(args, format); 464 | vfprintf(output, format, args); 465 | va_end(args); 466 | fprintf(output, ": %s\n", strerror(oerrno)); 467 | } 468 | 469 | 470 | /* 471 | * Allocate cleared memory, reporting a fatal error with bail on failure. 472 | */ 473 | void * 474 | bcalloc(size_t n, size_t size) 475 | { 476 | void *p; 477 | 478 | p = calloc(n, size); 479 | if (p == NULL) 480 | sysbail("failed to calloc %lu", (unsigned long)(n * size)); 481 | return p; 482 | } 483 | 484 | 485 | /* 486 | * Allocate memory, reporting a fatal error with bail on failure. 487 | */ 488 | void * 489 | bmalloc(size_t size) 490 | { 491 | void *p; 492 | 493 | p = malloc(size); 494 | if (p == NULL) 495 | sysbail("failed to malloc %lu", (unsigned long) size); 496 | return p; 497 | } 498 | 499 | 500 | /* 501 | * Reallocate memory, reporting a fatal error with bail on failure. 502 | */ 503 | void * 504 | brealloc(void *p, size_t size) 505 | { 506 | p = realloc(p, size); 507 | if (p == NULL) 508 | sysbail("failed to realloc %lu bytes", (unsigned long) size); 509 | return p; 510 | } 511 | 512 | 513 | /* 514 | * Copy a string, reporting a fatal error with bail on failure. 515 | */ 516 | char * 517 | bstrdup(const char *s) 518 | { 519 | char *p; 520 | size_t len; 521 | 522 | len = strlen(s) + 1; 523 | p = malloc(len); 524 | if (p == NULL) 525 | sysbail("failed to strdup %lu bytes", (unsigned long) len); 526 | memcpy(p, s, len); 527 | return p; 528 | } 529 | 530 | 531 | /* 532 | * Copy up to n characters of a string, reporting a fatal error with bail on 533 | * failure. Don't use the system strndup function, since it may not exist and 534 | * the TAP library doesn't assume any portability support. 535 | */ 536 | char * 537 | bstrndup(const char *s, size_t n) 538 | { 539 | const char *p; 540 | char *copy; 541 | size_t length; 542 | 543 | /* Don't assume that the source string is nul-terminated. */ 544 | for (p = s; (size_t) (p - s) < n && *p != '\0'; p++) 545 | ; 546 | length = p - s; 547 | copy = malloc(length + 1); 548 | if (p == NULL) 549 | sysbail("failed to strndup %lu bytes", (unsigned long) length); 550 | memcpy(copy, s, length); 551 | copy[length] = '\0'; 552 | return copy; 553 | } 554 | 555 | 556 | /* 557 | * Locate a test file. Given the partial path to a file, look under BUILD and 558 | * then SOURCE for the file and return the full path to the file. Returns 559 | * NULL if the file doesn't exist. A non-NULL return should be freed with 560 | * test_file_path_free(). 561 | * 562 | * This function uses sprintf because it attempts to be independent of all 563 | * other portability layers. The use immediately after a memory allocation 564 | * should be safe without using snprintf or strlcpy/strlcat. 565 | */ 566 | char * 567 | test_file_path(const char *file) 568 | { 569 | char *base; 570 | char *path = NULL; 571 | size_t length; 572 | const char *envs[] = { "BUILD", "SOURCE", NULL }; 573 | int i; 574 | 575 | for (i = 0; envs[i] != NULL; i++) { 576 | base = getenv(envs[i]); 577 | if (base == NULL) 578 | continue; 579 | length = strlen(base) + 1 + strlen(file) + 1; 580 | path = bmalloc(length); 581 | sprintf(path, "%s/%s", base, file); 582 | if (access(path, R_OK) == 0) 583 | break; 584 | free(path); 585 | path = NULL; 586 | } 587 | return path; 588 | } 589 | 590 | 591 | /* 592 | * Free a path returned from test_file_path(). This function exists primarily 593 | * for Windows, where memory must be freed from the same library domain that 594 | * it was allocated from. 595 | */ 596 | void 597 | test_file_path_free(char *path) 598 | { 599 | if (path != NULL) 600 | free(path); 601 | } 602 | 603 | 604 | /* 605 | * Create a temporary directory, tmp, under BUILD if set and the current 606 | * directory if it does not. Returns the path to the temporary directory in 607 | * newly allocated memory, and calls bail on any failure. The return value 608 | * should be freed with test_tmpdir_free. 609 | * 610 | * This function uses sprintf because it attempts to be independent of all 611 | * other portability layers. The use immediately after a memory allocation 612 | * should be safe without using snprintf or strlcpy/strlcat. 613 | */ 614 | char * 615 | test_tmpdir(void) 616 | { 617 | const char *build; 618 | char *path = NULL; 619 | size_t length; 620 | 621 | build = getenv("BUILD"); 622 | if (build == NULL) 623 | build = "."; 624 | length = strlen(build) + strlen("/tmp") + 1; 625 | path = bmalloc(length); 626 | sprintf(path, "%s/tmp", build); 627 | if (access(path, X_OK) < 0) 628 | if (mkdir(path, 0777) < 0) 629 | sysbail("error creating temporary directory %s", path); 630 | return path; 631 | } 632 | 633 | 634 | /* 635 | * Free a path returned from test_tmpdir() and attempt to remove the 636 | * directory. If we can't delete the directory, don't worry; something else 637 | * that hasn't yet cleaned up may still be using it. 638 | */ 639 | void 640 | test_tmpdir_free(char *path) 641 | { 642 | rmdir(path); 643 | if (path != NULL) 644 | free(path); 645 | } 646 | -------------------------------------------------------------------------------- /tools/tests/tap/basic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Basic utility routines for the TAP protocol. 3 | * 4 | * This file is part of C TAP Harness. The current version plus supporting 5 | * documentation is at . 6 | * 7 | * Copyright 2009, 2010, 2011, 2012 Russ Allbery 8 | * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 9 | * The Board of Trustees of the Leland Stanford Junior University 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a 12 | * copy of this software and associated documentation files (the "Software"), 13 | * to deal in the Software without restriction, including without limitation 14 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 | * and/or sell copies of the Software, and to permit persons to whom the 16 | * Software is furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in 19 | * all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | * DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | #ifndef TAP_BASIC_H 31 | #define TAP_BASIC_H 1 32 | 33 | #include 34 | #include /* va_list */ 35 | #include /* size_t */ 36 | 37 | /* 38 | * Used for iterating through arrays. ARRAY_SIZE returns the number of 39 | * elements in the array (useful for a < upper bound in a for loop) and 40 | * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it 41 | * legal to refer to such a pointer as long as it's never dereferenced). 42 | */ 43 | #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) 44 | #define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)]) 45 | 46 | BEGIN_DECLS 47 | 48 | /* 49 | * The test count. Always contains the number that will be used for the next 50 | * test status. 51 | */ 52 | extern unsigned long testnum; 53 | 54 | /* Print out the number of tests and set standard output to line buffered. */ 55 | void plan(unsigned long count); 56 | 57 | /* 58 | * Prepare for lazy planning, in which the plan will be printed automatically 59 | * at the end of the test program. 60 | */ 61 | void plan_lazy(void); 62 | 63 | /* Skip the entire test suite. Call instead of plan. */ 64 | void skip_all(const char *format, ...) 65 | __attribute__((__noreturn__, __format__(printf, 1, 2))); 66 | 67 | /* 68 | * Basic reporting functions. The okv() function is the same as ok() but 69 | * takes the test description as a va_list to make it easier to reuse the 70 | * reporting infrastructure when writing new tests. 71 | */ 72 | void ok(int success, const char *format, ...) 73 | __attribute__((__format__(printf, 2, 3))); 74 | void okv(int success, const char *format, va_list args); 75 | void skip(const char *reason, ...) 76 | __attribute__((__format__(printf, 1, 2))); 77 | 78 | /* Report the same status on, or skip, the next count tests. */ 79 | void ok_block(unsigned long count, int success, const char *format, ...) 80 | __attribute__((__format__(printf, 3, 4))); 81 | void skip_block(unsigned long count, const char *reason, ...) 82 | __attribute__((__format__(printf, 2, 3))); 83 | 84 | /* Check an expected value against a seen value. */ 85 | void is_int(long wanted, long seen, const char *format, ...) 86 | __attribute__((__format__(printf, 3, 4))); 87 | void is_string(const char *wanted, const char *seen, const char *format, ...) 88 | __attribute__((__format__(printf, 3, 4))); 89 | void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) 90 | __attribute__((__format__(printf, 3, 4))); 91 | 92 | /* Bail out with an error. sysbail appends strerror(errno). */ 93 | void bail(const char *format, ...) 94 | __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); 95 | void sysbail(const char *format, ...) 96 | __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); 97 | 98 | /* Report a diagnostic to stderr prefixed with #. */ 99 | void diag(const char *format, ...) 100 | __attribute__((__nonnull__, __format__(printf, 1, 2))); 101 | void sysdiag(const char *format, ...) 102 | __attribute__((__nonnull__, __format__(printf, 1, 2))); 103 | 104 | /* Allocate memory, reporting a fatal error with bail on failure. */ 105 | void *bcalloc(size_t, size_t) 106 | __attribute__((__alloc_size__(1, 2), __malloc__)); 107 | void *bmalloc(size_t) 108 | __attribute__((__alloc_size__(1), __malloc__)); 109 | void *brealloc(void *, size_t) 110 | __attribute__((__alloc_size__(2), __malloc__)); 111 | char *bstrdup(const char *) 112 | __attribute__((__malloc__, __nonnull__)); 113 | char *bstrndup(const char *, size_t) 114 | __attribute__((__malloc__, __nonnull__)); 115 | 116 | /* 117 | * Find a test file under BUILD or SOURCE, returning the full path. The 118 | * returned path should be freed with test_file_path_free(). 119 | */ 120 | char *test_file_path(const char *file) 121 | __attribute__((__malloc__, __nonnull__)); 122 | void test_file_path_free(char *path); 123 | 124 | /* 125 | * Create a temporary directory relative to BUILD and return the path. The 126 | * returned path should be freed with test_tmpdir_free. 127 | */ 128 | char *test_tmpdir(void) 129 | __attribute__((__malloc__)); 130 | void test_tmpdir_free(char *path); 131 | 132 | END_DECLS 133 | 134 | #endif /* TAP_BASIC_H */ 135 | -------------------------------------------------------------------------------- /tools/tests/tap/libtap.sh: -------------------------------------------------------------------------------- 1 | # Shell function library for test cases. 2 | # 3 | # Note that while many of the functions in this library could benefit from 4 | # using "local" to avoid possibly hammering global variables, Solaris /bin/sh 5 | # doesn't support local and this library aspires to be portable to Solaris 6 | # Bourne shell. Instead, all private variables are prefixed with "tap_". 7 | # 8 | # This file provides a TAP-compatible shell function library useful for 9 | # writing test cases. It is part of C TAP Harness, which can be found at 10 | # . 11 | # 12 | # Written by Russ Allbery 13 | # Copyright 2009, 2010, 2011, 2012 Russ Allbery 14 | # Copyright 2006, 2007, 2008 15 | # The Board of Trustees of the Leland Stanford Junior University 16 | # 17 | # Permission is hereby granted, free of charge, to any person obtaining a copy 18 | # of this software and associated documentation files (the "Software"), to 19 | # deal in the Software without restriction, including without limitation the 20 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 21 | # sell copies of the Software, and to permit persons to whom the Software is 22 | # furnished to do so, subject to the following conditions: 23 | # 24 | # The above copyright notice and this permission notice shall be included in 25 | # all copies or substantial portions of the Software. 26 | # 27 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 33 | # IN THE SOFTWARE. 34 | 35 | # Print out the number of test cases we expect to run. 36 | plan () { 37 | count=1 38 | planned="$1" 39 | failed=0 40 | echo "1..$1" 41 | trap finish 0 42 | } 43 | 44 | # Prepare for lazy planning. 45 | plan_lazy () { 46 | count=1 47 | planned=0 48 | failed=0 49 | trap finish 0 50 | } 51 | 52 | # Report the test status on exit. 53 | finish () { 54 | tap_highest=`expr "$count" - 1` 55 | if [ "$planned" = 0 ] ; then 56 | echo "1..$tap_highest" 57 | planned="$tap_highest" 58 | fi 59 | tap_looks='# Looks like you' 60 | if [ "$planned" -gt 0 ] ; then 61 | if [ "$planned" -gt "$tap_highest" ] ; then 62 | if [ "$planned" -gt 1 ] ; then 63 | echo "$tap_looks planned $planned tests but only ran" \ 64 | "$tap_highest" 65 | else 66 | echo "$tap_looks planned $planned test but only ran" \ 67 | "$tap_highest" 68 | fi 69 | elif [ "$planned" -lt "$tap_highest" ] ; then 70 | tap_extra=`expr "$tap_highest" - "$planned"` 71 | if [ "$planned" -gt 1 ] ; then 72 | echo "$tap_looks planned $planned tests but ran" \ 73 | "$tap_extra extra" 74 | else 75 | echo "$tap_looks planned $planned test but ran" \ 76 | "$tap_extra extra" 77 | fi 78 | elif [ "$failed" -gt 0 ] ; then 79 | if [ "$failed" -gt 1 ] ; then 80 | echo "$tap_looks failed $failed tests of $planned" 81 | else 82 | echo "$tap_looks failed $failed test of $planned" 83 | fi 84 | elif [ "$planned" -gt 1 ] ; then 85 | echo "# All $planned tests successful or skipped" 86 | else 87 | echo "# $planned test successful or skipped" 88 | fi 89 | fi 90 | } 91 | 92 | # Skip the entire test suite. Should be run instead of plan. 93 | skip_all () { 94 | tap_desc="$1" 95 | if [ -n "$tap_desc" ] ; then 96 | echo "1..0 # skip $tap_desc" 97 | else 98 | echo "1..0 # skip" 99 | fi 100 | exit 0 101 | } 102 | 103 | # ok takes a test description and a command to run and prints success if that 104 | # command is successful, false otherwise. The count starts at 1 and is 105 | # updated each time ok is printed. 106 | ok () { 107 | tap_desc="$1" 108 | if [ -n "$tap_desc" ] ; then 109 | tap_desc=" - $tap_desc" 110 | fi 111 | shift 112 | if "$@" ; then 113 | echo ok "$count$tap_desc" 114 | else 115 | echo not ok "$count$tap_desc" 116 | failed=`expr $failed + 1` 117 | fi 118 | count=`expr $count + 1` 119 | } 120 | 121 | # Skip the next test. Takes the reason why the test is skipped. 122 | skip () { 123 | echo "ok $count # skip $*" 124 | count=`expr $count + 1` 125 | } 126 | 127 | # Report the same status on a whole set of tests. Takes the count of tests, 128 | # the description, and then the command to run to determine the status. 129 | ok_block () { 130 | tap_i=$count 131 | tap_end=`expr $count + $1` 132 | shift 133 | while [ "$tap_i" -lt "$tap_end" ] ; do 134 | ok "$@" 135 | tap_i=`expr $tap_i + 1` 136 | done 137 | } 138 | 139 | # Skip a whole set of tests. Takes the count and then the reason for skipping 140 | # the test. 141 | skip_block () { 142 | tap_i=$count 143 | tap_end=`expr $count + $1` 144 | shift 145 | while [ "$tap_i" -lt "$tap_end" ] ; do 146 | skip "$@" 147 | tap_i=`expr $tap_i + 1` 148 | done 149 | } 150 | 151 | # Portable variant of printf '%s\n' "$*". In the majority of cases, this 152 | # function is slower than printf, because the latter is often implemented 153 | # as a builtin command. The value of the variable IFS is ignored. 154 | # 155 | # This macro must not be called via backticks inside double quotes, since this 156 | # will result in bizarre escaping behavior and lots of extra backslashes on 157 | # Solaris. 158 | puts () { 159 | cat << EOH 160 | $@ 161 | EOH 162 | } 163 | 164 | # Run a program expected to succeed, and print ok if it does and produces the 165 | # correct output. Takes the description, expected exit status, the expected 166 | # output, the command to run, and then any arguments for that command. 167 | # Standard output and standard error are combined when analyzing the output of 168 | # the command. 169 | # 170 | # If the command may contain system-specific error messages in its output, 171 | # add strip_colon_error before the command to post-process its output. 172 | ok_program () { 173 | tap_desc="$1" 174 | shift 175 | tap_w_status="$1" 176 | shift 177 | tap_w_output="$1" 178 | shift 179 | tap_output=`"$@" 2>&1` 180 | tap_status=$? 181 | if [ $tap_status = $tap_w_status ] \ 182 | && [ x"$tap_output" = x"$tap_w_output" ] ; then 183 | ok "$tap_desc" true 184 | else 185 | echo "# saw: ($tap_status) $tap_output" 186 | echo "# not: ($tap_w_status) $tap_w_output" 187 | ok "$tap_desc" false 188 | fi 189 | } 190 | 191 | # Strip a colon and everything after it off the output of a command, as long 192 | # as that colon comes after at least one whitespace character. (This is done 193 | # to avoid stripping the name of the program from the start of an error 194 | # message.) This is used to remove system-specific error messages (coming 195 | # from strerror, for example). 196 | strip_colon_error() { 197 | tap_output=`"$@" 2>&1` 198 | tap_status=$? 199 | tap_output=`puts "$tap_output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'` 200 | puts "$tap_output" 201 | return $tap_status 202 | } 203 | 204 | # Bail out with an error message. 205 | bail () { 206 | echo 'Bail out!' "$@" 207 | exit 1 208 | } 209 | 210 | # Output a diagnostic on standard error, preceded by the required # mark. 211 | diag () { 212 | echo '#' "$@" 213 | } 214 | 215 | # Search for the given file first in $BUILD and then in $SOURCE and echo the 216 | # path where the file was found, or the empty string if the file wasn't 217 | # found. 218 | # 219 | # This macro uses puts, so don't run it using backticks inside double quotes 220 | # or bizarre quoting behavior will happen with Solaris sh. 221 | test_file_path () { 222 | if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then 223 | puts "$BUILD/$1" 224 | elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then 225 | puts "$SOURCE/$1" 226 | else 227 | echo '' 228 | fi 229 | } 230 | 231 | # Create $BUILD/tmp for use by tests for storing temporary files and return 232 | # the path (via standard output). 233 | # 234 | # This macro uses puts, so don't run it using backticks inside double quotes 235 | # or bizarre quoting behavior will happen with Solaris sh. 236 | test_tmpdir () { 237 | if [ -z "$BUILD" ] ; then 238 | tap_tmpdir="./tmp" 239 | else 240 | tap_tmpdir="$BUILD"/tmp 241 | fi 242 | if [ ! -d "$tap_tmpdir" ] ; then 243 | mkdir "$tap_tmpdir" || bail "Error creating $tap_tmpdir" 244 | fi 245 | puts "$tap_tmpdir" 246 | } 247 | -------------------------------------------------------------------------------- /tools/tests/tap/macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Helpful macros for TAP header files. 3 | * 4 | * This is not, strictly speaking, related to TAP, but any TAP add-on is 5 | * probably going to need these macros, so define them in one place so that 6 | * everyone can pull them in. 7 | * 8 | * This file is part of C TAP Harness. The current version plus supporting 9 | * documentation is at . 10 | * 11 | * Copyright 2008, 2012 Russ Allbery 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a 14 | * copy of this software and associated documentation files (the "Software"), 15 | * to deal in the Software without restriction, including without limitation 16 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 17 | * and/or sell copies of the Software, and to permit persons to whom the 18 | * Software is furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 26 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | * DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | #ifndef TAP_MACROS_H 33 | #define TAP_MACROS_H 1 34 | 35 | /* 36 | * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7 37 | * could you use the __format__ form of the attributes, which is what we use 38 | * (to avoid confusion with other macros), and only with gcc 2.96 can you use 39 | * the attribute __malloc__. 2.96 is very old, so don't bother trying to get 40 | * the other attributes to work with GCC versions between 2.7 and 2.96. 41 | */ 42 | #ifndef __attribute__ 43 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 44 | # define __attribute__(spec) /* empty */ 45 | # endif 46 | #endif 47 | 48 | /* 49 | * We use __alloc_size__, but it was only available in fairly recent versions 50 | * of GCC. Suppress warnings about the unknown attribute if GCC is too old. 51 | * We know that we're GCC at this point, so we can use the GCC variadic macro 52 | * extension, which will still work with versions of GCC too old to have C99 53 | * variadic macro support. 54 | */ 55 | #if !defined(__attribute__) && !defined(__alloc_size__) 56 | # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) 57 | # define __alloc_size__(spec, args...) /* empty */ 58 | # endif 59 | #endif 60 | 61 | /* 62 | * LLVM and Clang pretend to be GCC but don't support all of the __attribute__ 63 | * settings that GCC does. For them, suppress warnings about unknown 64 | * attributes on declarations. This unfortunately will affect the entire 65 | * compilation context, but there's no push and pop available. 66 | */ 67 | #if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__)) 68 | # pragma GCC diagnostic ignored "-Wattributes" 69 | #endif 70 | 71 | /* Used for unused parameters to silence gcc warnings. */ 72 | #define UNUSED __attribute__((__unused__)) 73 | 74 | /* 75 | * BEGIN_DECLS is used at the beginning of declarations so that C++ 76 | * compilers don't mangle their names. END_DECLS is used at the end. 77 | */ 78 | #undef BEGIN_DECLS 79 | #undef END_DECLS 80 | #ifdef __cplusplus 81 | # define BEGIN_DECLS extern "C" { 82 | # define END_DECLS } 83 | #else 84 | # define BEGIN_DECLS /* empty */ 85 | # define END_DECLS /* empty */ 86 | #endif 87 | 88 | #endif /* TAP_MACROS_H */ 89 | -------------------------------------------------------------------------------- /tools/tests/tap/test_pkg.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright © 2010 Wesley J. Landaker 2 | -- 3 | -- This program is free software: you can redistribute it and/or modify 4 | -- it under the terms of the GNU General Public License as published by 5 | -- the Free Software Foundation, either version 3 of the License, or 6 | -- (at your option) any later version. 7 | 8 | -- 9 | -- This program is distributed in the hope that it will be useful, 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | -- GNU General Public License for more details. 13 | -- 14 | -- You should have received a copy of the GNU General Public License 15 | -- along with this program. If not, see . 16 | 17 | -- Output is standard TAP (Test Anything Protocol) version 13 18 | library ieee; 19 | use ieee.std_logic_1164.all; 20 | use ieee.numeric_std.all; 21 | use std.textio.all; 22 | use ieee.std_logic_textio.all; 23 | 24 | package test_pkg is 25 | 26 | function remove_eol(s : string) return string; 27 | procedure init; 28 | procedure test_redirect(filename : string); 29 | procedure test_plan(tests : natural; directive : string := ""); 30 | procedure test_abort(reason : string); 31 | procedure test_finished(directive : string := ""); 32 | procedure test_comment (message : string); 33 | procedure test_comment_fail (actual,expected : std_logic_vector); 34 | procedure test_pass (description : string := ""; directive : string := ""); 35 | procedure test_fail (description : string := ""; directive : string := ""); 36 | procedure test_ok (result : boolean; description : string := ""; directive : string := ""); 37 | procedure test_equal(actual, expected : integer; description : string := ""; directive : string := ""); 38 | 39 | procedure test_equal(actual, expected : std_logic_vector; description : string := ""; directive : string := ""); 40 | procedure test_equal(actual, expected : std_logic; description : string := ""; directive : string := ""); 41 | function slv(i,s : integer) return std_logic_vector; 42 | function slv(i : integer) return std_logic_vector; 43 | end package; 44 | 45 | 46 | 47 | package body test_pkg is 48 | 49 | file test_output : text; 50 | shared variable initialized : boolean := false; 51 | shared variable have_plan : boolean := false; 52 | shared variable last_test_number : natural := 0; 53 | 54 | function slv(i,s : integer) return std_logic_vector is 55 | variable r : std_logic_vector(s-1 downto 0); 56 | begin 57 | r := std_logic_vector(to_signed(i, s)); 58 | return r; 59 | end function slv; 60 | 61 | function slv(i : integer) return std_logic_vector is 62 | begin 63 | return slv(i, 32); 64 | end function slv; 65 | 66 | function remove_eol(s : string) return string is 67 | variable s_no_eol : string(s'range); 68 | begin 69 | for i in s'range loop 70 | case s(i) is 71 | when LF | CR => s_no_eol(i) := '_'; 72 | when others => s_no_eol(i) := s(i); 73 | end case; 74 | end loop; 75 | return s_no_eol; 76 | end function; 77 | 78 | function make_safe (s : string) return string is 79 | variable s_no_hash : string(s'range); 80 | begin 81 | for i in s'range loop 82 | case s(i) is 83 | when '#' => s_no_hash(i) := '_'; 84 | when others => s_no_hash(i) := s(i); 85 | end case; 86 | end loop; 87 | return remove_eol(s_no_hash); 88 | end function; 89 | 90 | procedure init is 91 | variable l : line; 92 | begin 93 | if initialized then 94 | return; 95 | end if; 96 | initialized := true; 97 | write(l, string'("TAP version 13")); 98 | writeline(output, l); 99 | end procedure; 100 | 101 | procedure test_redirect(filename : string) is 102 | begin 103 | init; 104 | end procedure; 105 | 106 | procedure test_plan(tests : natural; directive : string := "") is 107 | variable l : line; 108 | begin 109 | init; 110 | have_plan := true; 111 | write(l, string'("1..")); 112 | write(l, tests); 113 | if directive'length > 0 then 114 | write(l, " # " & remove_eol(directive)); 115 | end if; 116 | writeline(output, l); 117 | end procedure; 118 | 119 | procedure test_abort(reason : string) is 120 | variable l : line; 121 | begin 122 | init; 123 | write(l, "Bail out! " & remove_eol(reason)); 124 | writeline(test_output, l); 125 | assert false 126 | report "abort called" 127 | severity failure; 128 | end procedure; 129 | 130 | procedure test_finished (directive : string := "") is 131 | begin 132 | if not have_plan then 133 | test_plan(last_test_number, directive); 134 | elsif directive'length > 0 then 135 | test_comment("1.." & integer'image(last_test_number) & " # " & directive); 136 | else 137 | test_comment("1.." & integer'image(last_test_number)); 138 | end if; 139 | end procedure; 140 | 141 | procedure test_comment (message : string) is 142 | variable l : line; 143 | begin 144 | init; 145 | write(l, '#'); 146 | if message'length > 0 then 147 | write(l, " " & remove_eol(message)); 148 | end if; 149 | writeline(output, l); 150 | end procedure; 151 | 152 | procedure test_comment_fail (actual,expected : std_logic_vector) is 153 | variable l : line; 154 | begin 155 | init; 156 | if actual'length mod 4 = 0 and expected'length mod 4 = 0 then 157 | write(l, string'("# actual is x")); 158 | hwrite(l, actual); 159 | write(l, string'(" expected is x")); 160 | hwrite(l,expected); 161 | else 162 | write(l, string'("# actual is ")); 163 | write(l, actual); 164 | write(l, string'(" expected is ")); 165 | write(l,expected); 166 | end if; 167 | writeline(output, l); 168 | end procedure; 169 | 170 | procedure result (status : string; description : string; directive : string) is 171 | variable l : line; 172 | begin 173 | init; 174 | last_test_number := last_test_number + 1; 175 | write(l, status & " "); 176 | write(l, last_test_number); 177 | if description'length > 0 then 178 | write(l, " " & make_safe(description)); 179 | end if; 180 | if directive'length > 0 then 181 | write(l, " # " & remove_eol(directive)); 182 | end if; 183 | writeline(output, l); 184 | end procedure; 185 | 186 | procedure test_pass (description : string := ""; directive : string := "") is 187 | begin 188 | result("ok", description, directive); 189 | end procedure; 190 | 191 | procedure test_fail (description : string := ""; directive : string := "") is 192 | begin 193 | result("not ok", description, directive); 194 | end procedure; 195 | 196 | procedure test_ok (result : boolean; description : string := ""; directive : string := "") is 197 | begin 198 | if result then 199 | test_pass(description, directive); 200 | else 201 | test_fail(description, directive); 202 | end if; 203 | end procedure; 204 | 205 | procedure test_equal(actual, expected : integer; description : string := ""; directive : string := "") is 206 | variable ok : boolean := actual = expected; 207 | begin 208 | test_ok(ok, description, directive); 209 | if not ok then 210 | test_comment("actual = " & integer'image(actual) & ", expected = " & integer'image(expected)); 211 | end if; 212 | end procedure; 213 | 214 | procedure test_equal(actual, expected : std_logic_vector; 215 | description : string := ""; directive : string := "") is 216 | variable ok : boolean := actual = expected; 217 | begin 218 | if actual'length /= expected'length then 219 | test_comment_fail(actual,expected); 220 | test_comment("vector length mismatch"); 221 | test_ok(false, description, directive); 222 | else 223 | test_ok(ok, description, directive); 224 | if not ok then 225 | test_comment_fail(actual,expected); 226 | end if; 227 | end if; 228 | end procedure; 229 | 230 | procedure test_equal(actual, expected : std_logic; description : string := ""; directive : string := "") is 231 | variable ok : boolean := actual = expected; 232 | begin 233 | test_ok(ok, description, directive); 234 | end procedure; 235 | 236 | end package body; 237 | -------------------------------------------------------------------------------- /tools/v2p: -------------------------------------------------------------------------------- 1 | #!/opt/local/bin/perl 2 | 3 | # here is an ugly, straight forward C like attempt to parse .vhm 2 process 4 | # templates into clean VHDL. It might break, behave badly or even work. 5 | 6 | use feature ":5.10"; 7 | 8 | use strict; 9 | use IPC::Open2; 10 | 11 | # The state of the input, corresponds to entity, architecture, process... 12 | my $state = "none"; 13 | my $old_state = "none"; 14 | my $white = ""; 15 | 16 | # register variables and their attibutes from the arch decl 17 | my @regvar = (); 18 | my @regvar_type = (); 19 | my @regvar_rst = (); 20 | 21 | # strict wants these 22 | my ($i, $j, $line_valid, $entity); 23 | my (@list, @list_r); 24 | my ($old_white, $comment, $args); 25 | my ($arch, $sense); 26 | my ($rst_cond, $process, $regvar, $procvar, $clk_sig, $clk_cond, $rst_sig, $rst_sync); 27 | my (@procvar, @procvar_rst, @procvar_rsync, @procvar_clk); 28 | 29 | my @diversion = (); 30 | my @out = (); 31 | 32 | while() 33 | { 34 | my $line = $_; 35 | chomp($line); 36 | $line_valid = "yes"; 37 | 38 | # Separate the initial whitespace and comments from the code 39 | if ($line =~ m/^(\s*)(.*)(--.*)*$/) { 40 | $old_white = $white; 41 | $white = $1; 42 | $line = $2; 43 | $comment = $3; 44 | } 45 | 46 | # transformations go here, based on the current parser state 47 | given($state) { 48 | when ("none") { 49 | # look for entity and record the name 50 | if ($line =~ m/^(entity)(\s+)(\w+)(\s*.*)$/i) { 51 | $state = "entity"; 52 | $entity = lc($3); 53 | } 54 | } 55 | when ("entity") { 56 | # find the end of the entity section (well specified or not) 57 | if ($line =~ m/^(end)([\s+|;])(\w*)(\s*.*)$/i) { 58 | if (lc($3) eq $entity or lc($3) eq "entity" or lc($2) eq ";") { 59 | $state = "s_arch"; 60 | } 61 | } 62 | } 63 | when ("s_arch") { 64 | # look architecture declariation and check the entity name 65 | if ($line =~ m/^(architecture)(\s+)(\w+)(\s+of\s+)(\w+)(\s*.*)$/i) { 66 | if (lc($5) eq $entity) { 67 | $arch = lc($3); 68 | $state = "arch"; 69 | } 70 | } 71 | } 72 | when ("arch") { 73 | # look for the start of the architecture body 74 | if ($line =~ m/^(begin)(\s*.*)$/i) { 75 | $state = "body"; 76 | } 77 | # look for 'register variables' and insert signals for them 78 | if ($line =~ m/^(register)(\s+)(variable)(\s+)(\w+)(\s+)(:)(\s*)(.+)(\s+)(reset)(\s*)(:=)(\s*)(.+)(\s*);$/i) { 79 | push(@diversion, $white . "signal" . $2. $5 . "_c" . $6 . ":" . $8 . $9 . ";"); 80 | $line = "signal$2$5_r$6:$8$9;"; 81 | push(@regvar, $5); 82 | push(@regvar_type, $9); 83 | push(@regvar_rst, $15); 84 | } 85 | } 86 | when ("body") { 87 | # find the end of the architecture body (well specified or not) 88 | if ($line =~ m/^(end)(\s+)(\w+)(\s*.*)$/i) { 89 | if (lc($3) eq $arch or lc($3) eq "architecture") { 90 | @regvar = (); 91 | @regvar_type = (); 92 | @regvar_rst = (); 93 | $state = "none"; 94 | } 95 | } 96 | # find processes 97 | if ($line =~ m/^(\w*)(\s*:\s*)*(process)(\s*.*)$/i) { 98 | $line = "$1$2$3"; 99 | $process = $1; 100 | $sense = $4; 101 | if ($sense =~ m/^(\s*)\(([\w\s,]*)\)(\s*.*)$/i) { 102 | # parse the sensitivity list and add in the signals for register vars 103 | @list = split(',', $2); 104 | @list_r = (); 105 | foreach $i (@list) { 106 | if (grep {$_ eq $i} @regvar) { 107 | push(@list_r, $i . "_r"); 108 | } else { 109 | push(@list_r, $i); 110 | } 111 | } 112 | $args = join(',', @list_r); 113 | $line = "$line$1($args)$4"; 114 | } else { 115 | # empty sensitivity list 116 | $line = "$line()$4"; 117 | } 118 | @procvar = (); 119 | @procvar_rst = (); 120 | @procvar_rsync = (); 121 | @procvar_clk = (); 122 | $state = "s_process"; 123 | } 124 | } 125 | when ("s_process") { 126 | # look for register var register and reset conditions 127 | if ($line =~ m/^(register)(\s+)(\w+)(\s+)(when)(\s+)(.+)(\s+)(reset)(\s*)(sync)?(\s+)(when)(\s+)(.*);$/i) { 128 | $clk_cond = $7; 129 | $rst_sync = $11; 130 | $rst_cond = $15; 131 | push(@procvar, $3); 132 | push(@procvar_rst, $rst_cond); 133 | push(@procvar_rsync, $rst_sync); 134 | push(@procvar_clk, $clk_cond); 135 | 136 | $line_valid = ""; 137 | $j = 0; 138 | foreach $regvar(@regvar) { 139 | if ($regvar[$j] eq $3) { 140 | push(@diversion, $white . "variable " . $3 . " : " . $regvar_type[$j] . ";"); 141 | } 142 | $j++; 143 | } 144 | } 145 | # look for the start of the process body 146 | if ($line =~ m/^(begin)(\s*.*)$/i) { 147 | $state = "process"; 148 | push(@diversion, $white . $line . $comment); 149 | $i = 0; 150 | foreach $procvar(@procvar) { 151 | push(@diversion, $white . " " . $procvar[$i] . " := " . $procvar[$i] . "_r;"); 152 | $i++; 153 | } 154 | if ($i>0) { 155 | push(@diversion, ""); 156 | } 157 | $line_valid = ""; 158 | } 159 | } 160 | when ("process") { 161 | # find the end of the process body 162 | if ($line =~ m/^(end)(\s+)(\w+)(\s*.*)$/i) { 163 | if (lc($3) eq "process") { 164 | $state = "body"; 165 | $line_valid = ""; 166 | 167 | push(@diversion, ""); 168 | foreach $procvar(@procvar) { 169 | push(@diversion, $old_white . $procvar . "_c <= " . $procvar . ";"); 170 | } 171 | push(@diversion, $white . $line . $comment); 172 | 173 | $i = 0; 174 | foreach $procvar(@procvar) { 175 | 176 | $j = 0; 177 | foreach $regvar(@regvar) { 178 | if ($regvar[$j] eq $procvar[$i]) { 179 | $rst_cond = $regvar_rst[$j]; 180 | } 181 | $j++; 182 | } 183 | 184 | push(@diversion, ""); 185 | $procvar_clk[$i] =~ m/^(\s*)(\w+)/; 186 | $clk_sig = $2; 187 | 188 | $procvar_rst[$i] =~ m/^(\s*)(\w+)/; 189 | $rst_sig = $2; 190 | 191 | push(@diversion, $white . $process . "_r" . $i . " : process(" . $clk_sig . ", " . $rst_sig . ")"); 192 | push(@diversion, $white . "begin"); 193 | 194 | if ($procvar_rsync[$i] =~ m/sync.*/i) { 195 | push(@diversion, $white . " if " . $procvar_clk[$i] . " then"); 196 | push(@diversion, $white . " if " . $procvar_rst[$i] . " then"); 197 | push(@diversion, $white . " " . $procvar[$i] . "_r <= " . $rst_cond . ";"); 198 | push(@diversion, $white . " else"); 199 | push(@diversion, $white . " " . $procvar[$i] . "_r <= " . $procvar[$i] . "_c;"); 200 | push(@diversion, $white . " end if;"); 201 | push(@diversion, $white . " end if;"); 202 | push(@diversion, $white . "end process;"); 203 | } else { 204 | push(@diversion, $white . " if " . $procvar_rst[$i] . " then"); 205 | push(@diversion, $white . " " . $procvar[$i] . "_r <= " . $rst_cond . ";"); 206 | push(@diversion, $white . " elsif " . $procvar_clk[$i] . " then"); 207 | push(@diversion, $white . " " . $procvar[$i] . "_r <= " . $procvar[$i] . "_c;"); 208 | push(@diversion, $white . " end if;"); 209 | push(@diversion, $white . "end process;"); 210 | } 211 | $i++; 212 | } 213 | } 214 | } 215 | } 216 | } 217 | 218 | if ($state ne $old_state) { 219 | foreach $i (@diversion) { 220 | #print "$i\n"; 221 | push @out => $i; 222 | } 223 | @diversion = (); 224 | $old_state = $state; 225 | } 226 | # look for register or comb attribute, replace it. FIXME: wrong place, no error checking. 227 | if ($line_valid eq "yes") { 228 | $line =~ s/(\w)\'register/$1_r/gi; 229 | $line =~ s/(\w)\'combinatorial/$1_c/gi; 230 | $line =~ s/(\w)\'comb/$1_c/gi; 231 | push(@diversion, "$white$line$comment"); 232 | } 233 | } 234 | 235 | foreach $i (@diversion) { 236 | #print "$i\n"; 237 | push @out => $i; 238 | } 239 | #my $count = 1; 240 | #printf("-- %03d: %s\n", $count++, $_) for @out; 241 | 242 | my($chld_out, $chld_in); 243 | #my $pid = open2($chld_out, $chld_in, 'cpp -w -P -nostdinc -I.'); 244 | my $pid = open2($chld_out, $chld_in, 'gcc -E -P -x c -nostdinc -DVHDL -I. -'); 245 | print $chld_in join("\n" => @out); close($chld_in); 246 | my @cpp_out = <$chld_out>; 247 | waitpid( $pid, 0 ); close($chld_out); 248 | my $child_exit_status = $? >> 8; 249 | 250 | for(@cpp_out) { 251 | next if $_ =~ /^#/; 252 | print; 253 | } 254 | --------------------------------------------------------------------------------