URL
https://opencores.org/ocsvn/wbscope/wbscope/trunk
Subversion Repositories wbscope
Compare Revisions
- This comparison shows the changes necessary to convert path
/wbscope
- from Rev 5 to Rev 6
- ↔ Reverse comparison
Rev 5 → Rev 6
/trunk/rtl/wbscopc.v
5,20 → 5,27
// Project: FPGA Library of Routines |
// |
// Purpose: This scope is identical in function to the wishbone scope |
// found in wbscope, save that the output is compressed and that |
// (as a result) it can only handle recording 31 bits at a time. |
// This allows the top bit to indicate an 'address'. |
// found in wbscope, save that the output is compressed and that (as a |
// result) it can only handle recording 31 bits at a time. This allows |
// the top bit to indicate an 'address difference'. Okay, there's |
// another difference as well: this version only works in a synchronous |
// fashion with the clock from the WB bus. You cannot have a separate |
// bus and data clock. |
// |
// Reading/decompressing the output of this scope works in this |
// fashion: clear a memory. Then, once the scope has stopped, |
// read from the port. If it's an address (high bit set), then |
// jump to that address. If it's not, then write into that |
// memory location and increment the memory address after writing. |
// Reading/decompressing the output of this scope works in this fashion: |
// Once the scope has stopped, read from the port. Any time the high |
// order bit is set, the other 31 bits tell you how many times to repeat |
// the last value. If the high order bit is not set, then the value |
// is a new data value. |
// |
// I've provided this version of a compressed scope to OpenCores for |
// discussion purposes. While wbscope.v works and works well by itself, |
// this compressed scope has a fundamental flaw that I have yet to fix: |
// The first values out of the scope take place at an unknown address. |
// this compressed scope has a couple of fundamental flaw that I have |
// yet to fix. One of them is that it is impossible to know when the |
// trigger took place. The second problem is that it may be impossible |
// to know the state of the scope at the beginning of the buffer--should |
// the buffer begin with an address difference value instead of a data |
// value. |
// |
// Ideally, the first item read out of the scope should be a data value, |
// even if the scope was skipping values to a new address at the time. |
32,6 → 39,15
// not because it runs nor because I have recognized that it has any |
// particular value (yet). |
// |
// Well, I take that back. When dealing with an interface such as the |
// PS/2 interface, or even the 16x2 LCD interface, it is often true |
// that things change _very_ slowly. They could change so slowly that |
// the other approach to the scope doesn't work. This then gives you |
// a working scope, by only capturing the changes. You'll still need |
// to figure out (after the fact) when the trigge took place. Perhaps |
// you'll wish to add the trigger as another data line, so you can find |
// when it took place in your own data? |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
83,20 → 99,43
|
// Let's first see how far we can get by cheating. We'll use the |
// wbscope program, and suffer a lack of several features |
|
// When is the full scope reset? Capture that reset bit from any |
// write. |
wire lcl_reset; |
assign lcl_reset = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_addr)&&(i_wb_we) |
&&(~i_wb_data[31]); |
|
// A big part of this scope is the 'address' of any particular |
// data value. As of this current version, the 'address' changed |
// in definition from an absolute time (which had all kinds of |
// problems) to a difference in time. Hence, when the address line |
// is high on decompression, the 'address' field will record an |
// address difference. |
// |
// To implement this, we set our 'address' to zero any time the |
// data changes, but increment it on all other clocks. Should the |
// address difference get to our maximum value, we let it saturate |
// rather than overflow. |
reg [(BUSW-2):0] ck_addr; |
initial ck_addr = 0; |
always @(posedge i_clk) |
if (lcl_reset) |
if ((lcl_reset)||((i_ce)&&(i_data != lst_data))) |
ck_addr <= 0; |
else if (&ck_addr) |
; // Saturated (non-overflowing) address diff |
else |
ck_addr <= ck_addr + 1; |
|
reg imm_adr, lst_adr; |
reg [(BUSW-2):0] lst_dat, lst_val, imm_val; |
// |
// To do our compression, we keep track of two registers: the most |
// recent data to the device (imm_ prefix) and the data from one |
// clock ago. This allows us to suppress writes to the scope which |
// would otherwise be two address writes in a row. |
reg imm_adr, lst_adr; // Is this an address (1'b1) or data value? |
reg [(BUSW-2):0] lst_dat, // The data associated with t-1 |
lst_val, // Data for the scope, delayed by one |
imm_val; // Data to write to the scope |
initial lst_dat = 0; |
initial lst_adr = 1'b1; |
initial imm_adr = 1'b1; |
116,12 → 155,16
lst_adr <= imm_adr; |
lst_dat <= i_data; |
end else begin |
imm_val <= ck_addr; |
imm_val <= ck_addr; // Minimum value here is '1' |
imm_adr <= 1'b1; |
lst_val <= imm_val; |
lst_adr <= imm_adr; |
end |
|
// |
// Here's where we suppress writing pairs of address words to the |
// scope at once. |
// |
reg r_ce; |
reg [(BUSW-1):0] r_data; |
initial r_ce = 1'b0; |
132,9 → 175,11
? { lst_adr, lst_val } |
: { 1'b0, i_data }; |
|
|
wbscope #(.SYNCHRONOUS(1), |
.LGMEM(LGMEM), |
// |
// Call the regular wishbone scope to do all of our real work, now |
// that we've compressed the input. |
// |
wbscope #(.SYNCHRONOUS(1), .LGMEM(LGMEM), |
.BUSW(BUSW)) cheatersscope(i_clk, r_ce, i_trigger, r_data, |
i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, o_interrupt); |
/trunk/doc/spec.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/doc/src/spec.tex
86,7 → 86,7
|
When I then needed to make the project run in real-time, as opposed to the |
manually stepped approach, I generated a scope like this one. I had already |
bench tested the components on the hardware itself. Thu, testing and |
bench tested the components on the hardware itself. Thus, testing and |
development continued on the hardware, and the scope helped me see what was |
going right or wrong. The great advantage of the approach was that, at the |
end of the project, I didn't need to do any hardware in the loop testing. |
160,27 → 160,30
|
Let's go through that list again. First, before using the scope, the holdoff |
needs to be set. The scope is designed so that setting the scope control value |
to the holdoff alone will reset the scope from whatever condition it was in, |
to the holdoff alone, with all other bits set to zero, will reset the scope |
from whatever condition it was in, |
freeing it to run. Once running, then upon every clock enabled clock, one |
sample of data is read into the scope and recorded. Once every memory value |
is filled, the scope has been {\tt PRIMED}. Once the scope has been |
{\tt PRIMED}, it will then be responsive to its trigger. Should the trigger be |
active on a clock--enabled input, the scope will then be {\tt TRIGGERED}. It |
active on an input clock with the clock--enable line set, the scope will then |
be {\tt TRIGGERED}. It |
will then count for the number of clocks in the holdoff before stopping |
collection, placing it in the {\tt STOPPED} state. (Don't change the holdoff |
during between triggered and stopped, or it may stop at some other non--holdoff |
value!) If the holdoff is zero, the last sample in the buffer will be the |
sample containing the trigger. Likewise if the holdoff is one less than the |
size of the memory, the first sample in the buffer will be the one containing |
the trigger. |
collection, placing it in the {\tt STOPPED} state. \footnote{You can even |
change the holdoff while the scope is running by writing a new holdoff value |
together with setting the {\tt RESET\_n} bit of the control register. However, |
if you do this after the core has triggered it may stop at some other |
non--holdoff value!} If the holdoff is zero, the last sample in the buffer |
will be the sample containing the trigger. Likewise if the holdoff is one |
less than the size of the memory, the first sample in the buffer will be the |
one containing the trigger. |
|
There are two further commands that will affect the operation of the scope. The |
first is the {\tt MANUAL} trigger command/bit. This bit may be set by writing |
the holdoff to the control register while setting this bit high. This will |
cause the scope to trigger immediately. If coupled with a {\tt RESET} command, |
that is if the {\tt RESET\_n} bit isn't also set, then recording will start |
at the beginning and the scope will first wait until its {\tt PRIMED} state |
before the manual trigger takes effect. |
cause the scope to trigger as soon as it is primed. If the {\tt RESET\_n} |
bit is also set so as to prevent an internal reset, and if the scope was already |
primed, then manual trigger command will cause it to trigger immediately. |
|
The last command that can affect the operation of the scope is the {\tt DISABLE} |
command/bit in the control register. Setting this bit will prevent the scope |
192,10 → 195,11
reasonable amount of time. |
|
So, in summary, to use this scope you first set the holdoff value in the |
control register. Second, you wait until the scope has been {\tt TRIGGERED} and |
stopped. Finally, you read from the data register once for every memory value |
in the buffer and you can then sit back, relax, and study what took place |
within the FPGA. |
control register. Second, you wait until the scope has been {\tt TRIGGERED} |
and {\tt STOPPED}. Finally, you read from the data register once for every |
memory value in the buffer and you can then sit back, relax, and study what |
took place within the FPGA. Additional modes allow you to manually trigger |
the scope, or to disable the automatic trigger entirely. |
|
\chapter{Registers} |
|
331,7 → 335,11
registers become 32--bit reads and writes to this interface. You may also wish |
to note that the scope supports pipeline reads from the data port, to speed |
up reading the results out. |
|
|
What this table doesn't show is that all accesses to the port take a single |
clock. That is, if the {\tt i\_wb\_stb} line is high on one clock, the |
{\tt i\_wb\_ack} line will be high the next. Further, the {\tt o\_wb\_stall} |
line is tied to zero. |
\chapter{IO Ports} |
|
The ports are listed in Table.~\ref{tbl:ioports}. |