OpenCores
URL https://opencores.org/ocsvn/wbscope/wbscope/trunk

Subversion Repositories wbscope

[/] [wbscope/] [trunk/] [rtl/] [wbscopc.v] - Blame information for rev 6

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 dgisselq
///////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    wbscopc.v
4
//
5
// Project:     FPGA Library of Routines
6
//
7
// Purpose:     This scope is identical in function to the wishbone scope
8 6 dgisselq
//      found in wbscope, save that the output is compressed and that (as a
9
//      result) it can only handle recording 31 bits at a time.  This allows
10
//      the top bit to indicate an 'address difference'.   Okay, there's 
11
//      another difference as well: this version only works in a synchronous
12
//      fashion with the clock from the WB bus.  You cannot have a separate
13
//      bus and data clock.
14 3 dgisselq
//
15 6 dgisselq
//      Reading/decompressing the output of this scope works in this fashion:
16
//      Once the scope has stopped, read from the port.  Any time the high
17
//      order bit is set, the other 31 bits tell you how many times to repeat
18
//      the last value.  If the high order bit is not set, then the value
19
//      is a new data value.
20 3 dgisselq
//
21
//      I've provided this version of a compressed scope to OpenCores for
22
//      discussion purposes.  While wbscope.v works and works well by itself,
23 6 dgisselq
//      this compressed scope has a couple of fundamental flaw that I have
24
//      yet to fix.  One of them is that it is impossible to know when the
25
//      trigger took place.  The second problem is that it may be impossible
26
//      to know the state of the scope at the beginning of the buffer--should
27
//      the buffer begin with an address difference value instead of a data
28
//      value.
29 3 dgisselq
//
30
//      Ideally, the first item read out of the scope should be a data value,
31
//      even if the scope was skipping values to a new address at the time.
32
//      If it was in the middle of a skip, the next item out of the scope
33
//      should be the skip length.  This, though, violates the rule that there
34
//      are (1<<LGMEMLEN) items in the memory, and that the trigger took place
35
//      on the last item of memory ... so that portion of this compressed
36
//      scope is still to be defined.
37
//
38
//      Like I said, this version is placed here for discussion purposes,
39
//      not because it runs nor because I have recognized that it has any
40
//      particular value (yet).
41
//
42 6 dgisselq
//      Well, I take that back.  When dealing with an interface such as the
43
//      PS/2 interface, or even the 16x2 LCD interface, it is often true
44
//      that things change _very_ slowly.  They could change so slowly that
45
//      the other approach to the scope doesn't work.  This then gives you
46
//      a working scope, by only capturing the changes.  You'll still need
47
//      to figure out (after the fact) when the trigge took place.  Perhaps
48
//      you'll wish to add the trigger as another data line, so you can find
49
//      when it took place in your own data?
50
//
51 3 dgisselq
// Creator:     Dan Gisselquist, Ph.D.
52
//              Gisselquist Tecnology, LLC
53
//
54
///////////////////////////////////////////////////////////////////////////
55
//
56
// Copyright (C) 2015, Gisselquist Technology, LLC
57
//
58
// This program is free software (firmware): you can redistribute it and/or
59
// modify it under the terms of  the GNU General Public License as published
60
// by the Free Software Foundation, either version 3 of the License, or (at
61
// your option) any later version.
62
//
63
// This program is distributed in the hope that it will be useful, but WITHOUT
64
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
65
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
66
// for more details.
67
//
68
// You should have received a copy of the GNU General Public License along
69
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
70
// target there if the PDF file isn't present.)  If not, see
71
// <http://www.gnu.org/licenses/> for a copy.
72
//
73
// License:     GPL, v3, as defined and found on www.gnu.org,
74
//              http://www.gnu.org/licenses/gpl.html
75
//
76
//
77
/////////////////////////////////////////////////////////////////////////////
78
//
79
//
80
module wbscopc(i_clk, i_ce, i_trigger, i_data,
81
        i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
82
        o_wb_ack, o_wb_stall, o_wb_data,
83
        o_interrupt);
84
        parameter       LGMEM = 5'd10, BUSW = 32, SYNCHRONOUS=1;
85
        // The input signals that we wish to record
86
        input                           i_clk, i_ce, i_trigger;
87
        input           [(BUSW-2):0]     i_data;
88
        // The WISHBONE bus for reading and configuring this scope
89
        input                           i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we;
90
        input                           i_wb_addr; // One address line only
91
        input           [(BUSW-1):0]     i_wb_data;
92
        output  wire                    o_wb_ack, o_wb_stall;
93
        output  wire    [(BUSW-1):0]     o_wb_data;
94
        // And, finally, for a final flair --- offer to interrupt the CPU after
95
        // our trigger has gone off.  This line is equivalent to the scope 
96
        // being stopped.  It is not maskable here.
97
        output  wire                    o_interrupt;
98
 
99
 
100
        // Let's first see how far we can get by cheating.  We'll use the
101
        // wbscope program, and suffer a lack of several features
102 6 dgisselq
 
103
        // When is the full scope reset?  Capture that reset bit from any
104
        // write.
105 3 dgisselq
        wire    lcl_reset;
106
        assign  lcl_reset = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_addr)&&(i_wb_we)
107
                                &&(~i_wb_data[31]);
108
 
109 6 dgisselq
        // A big part of this scope is the 'address' of any particular
110
        // data value.  As of this current version, the 'address' changed
111
        // in definition from an absolute time (which had all kinds of
112
        // problems) to a difference in time.  Hence, when the address line
113
        // is high on decompression, the 'address' field will record an
114
        // address difference.
115
        //
116
        // To implement this, we set our 'address' to zero any time the
117
        // data changes, but increment it on all other clocks.  Should the
118
        // address difference get to our maximum value, we let it saturate
119
        // rather than overflow.
120 3 dgisselq
        reg     [(BUSW-2):0]     ck_addr;
121
        initial ck_addr = 0;
122
        always @(posedge i_clk)
123 6 dgisselq
                if ((lcl_reset)||((i_ce)&&(i_data != lst_data)))
124 3 dgisselq
                        ck_addr <= 0;
125 6 dgisselq
                else if (&ck_addr)
126
                        ;       // Saturated (non-overflowing) address diff
127 3 dgisselq
                else
128
                        ck_addr <= ck_addr + 1;
129
 
130 6 dgisselq
        //
131
        // To do our compression, we keep track of two registers: the most
132
        // recent data to the device (imm_ prefix) and the data from one
133
        // clock ago.  This allows us to suppress writes to the scope which
134
        // would otherwise be two address writes in a row.
135
        reg     imm_adr, lst_adr; // Is this an address (1'b1) or data value?
136
        reg     [(BUSW-2):0]     lst_dat, // The data associated with t-1
137
                                lst_val, // Data for the scope, delayed by one
138
                                imm_val; // Data to write to the scope
139 3 dgisselq
        initial lst_dat = 0;
140
        initial lst_adr = 1'b1;
141
        initial imm_adr = 1'b1;
142
        always @(posedge i_clk)
143
                if (lcl_reset)
144
                begin
145
                        imm_val <= 31'h0;
146
                        imm_adr <= 1'b1;
147
                        lst_val <= 31'h0;
148
                        lst_adr <= 1'b1;
149
                        lst_dat <= 31'b0;
150
                end else if ((i_ce)&&(i_data != lst_dat))
151
                begin
152
                        imm_val <= i_data;
153
                        imm_adr <= 1'b0;
154
                        lst_val <= imm_val;
155
                        lst_adr <= imm_adr;
156
                        lst_dat <= i_data;
157
                end else begin
158 6 dgisselq
                        imm_val <= ck_addr; // Minimum value here is '1'
159 3 dgisselq
                        imm_adr <= 1'b1;
160
                        lst_val <= imm_val;
161
                        lst_adr <= imm_adr;
162
                end
163
 
164 6 dgisselq
        //
165
        // Here's where we suppress writing pairs of address words to the
166
        // scope at once.
167
        //
168 3 dgisselq
        reg                     r_ce;
169
        reg     [(BUSW-1):0]     r_data;
170
        initial                 r_ce = 1'b0;
171
        always @(posedge i_clk)
172
                r_ce <= (~lst_adr)||(~imm_adr);
173
        always @(posedge i_clk)
174
                r_data <= ((~lst_adr)||(~imm_adr))
175
                        ? { lst_adr, lst_val }
176
                        : { 1'b0, i_data };
177
 
178 6 dgisselq
        //
179
        // Call the regular wishbone scope to do all of our real work, now
180
        // that we've compressed the input.
181
        //
182
        wbscope #(.SYNCHRONOUS(1), .LGMEM(LGMEM),
183 3 dgisselq
                .BUSW(BUSW))    cheatersscope(i_clk, r_ce, i_trigger, r_data,
184
                i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
185
                o_wb_ack, o_wb_stall, o_wb_data, o_interrupt);
186
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.