Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 78f3629a8f37
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6b2b8744c1e6
Choose a head ref
  • 1 commit
  • 4 files changed
  • 1 contributor

Commits on Sep 5, 2020

  1. Copy the full SHA
    6b2b874 View commit details
Showing with 223 additions and 31 deletions.
  1. +25 −0 scopehal/PacketDecoder.cpp
  2. +3 −0 scopehal/PacketDecoder.h
  3. +185 −31 scopeprotocols/SPIFlashDecoder.cpp
  4. +10 −0 scopeprotocols/SPIFlashDecoder.h
25 changes: 25 additions & 0 deletions scopehal/PacketDecoder.cpp
Original file line number Diff line number Diff line change
@@ -63,3 +63,28 @@ bool PacketDecoder::GetShowImageColumn()
{
return false;
}

/**
@brief Checks if two packets can be merged under a single heading in the protocol analyzer view.
This can be used to collapse polling loops, acknowledgements, etc in order to minimize clutter in the view.
The default implementation in PacketDecoder always returns false so packets are not merged.
@param a Packet 1
@param b Packet 2
@return true if packets can be merged, false otherwise
*/
bool PacketDecoder::CanMerge(Packet* /*a*/, Packet* /*b*/)
{
return false;
}

/**
@brief Creates a summary packet for one or more merged packets
*/
Packet* PacketDecoder::CreateMergedHeader(Packet* /*pack*/)
{
return NULL;
}
3 changes: 3 additions & 0 deletions scopehal/PacketDecoder.h
Original file line number Diff line number Diff line change
@@ -72,6 +72,9 @@ class PacketDecoder : public Filter
virtual bool GetShowDataColumn();
virtual bool GetShowImageColumn();

virtual Packet* CreateMergedHeader(Packet* pack);
virtual bool CanMerge(Packet* a, Packet* b);

protected:
void ClearPackets();

216 changes: 185 additions & 31 deletions scopeprotocols/SPIFlashDecoder.cpp
Original file line number Diff line number Diff line change
@@ -145,7 +145,7 @@ void SPIFlashDecoder::Refresh()
STATE_QUAD_ADDRESS,
STATE_ADDRESS,
STATE_READ_DATA,
STATE_READ_QUAD_DATA,
STATE_QUAD_DATA,
STATE_WRITE_DATA,
STATE_DUMMY_BEFORE_ADDRESS,
STATE_DUMMY_BEFORE_DATA
@@ -186,21 +186,52 @@ void SPIFlashDecoder::Refresh()
//Parse the command
switch(s.m_data)
{
//Reset should occur by itself, ignore any data after that
case 0xff:
current_cmd = SPIFlashSymbol::CMD_RESET;
////////////////////////////////////////////////////////////////////////////////////////////////
// JEDEC standard commands (in numerical order)

//Write the status register
//TODO: address is W25N specific
case 0x01:
case 0x1f:
current_cmd = SPIFlashSymbol::CMD_WRITE_STATUS_REGISTER;
state = STATE_ADDRESS;
address_bytes_left = 1;
addr = 0;
addr_start = din->m_offsets[iin+1];
break;

//x1 program
case 0x02:
current_cmd = SPIFlashSymbol::CMD_PAGE_PROGRAM;
state = STATE_ADDRESS;
address_bytes_left = 2; //TODO: this is device specific, current value is for W25N
addr = 0;
addr_start = din->m_offsets[iin+1];
break;

//Slow read (no dummy clocks)
case 0x03:
current_cmd = SPIFlashSymbol::CMD_READ;
state = STATE_ADDRESS;
address_bytes_left = 2; //TODO: this is device specific, current value is for W25N
addr = 0;
addr_start = din->m_offsets[iin+1];
break;

//Clear write enable flag
case 0x04:
current_cmd = SPIFlashSymbol::CMD_WRITE_DISABLE;
state = STATE_IDLE;
break;

//Read the IDCODE
case 0x9f:
current_cmd = SPIFlashSymbol::CMD_READ_JEDEC_ID;
state = STATE_DUMMY_BEFORE_DATA;
data_type = SPIFlashSymbol::TYPE_VENDOR_ID;
//Set write enable flag
case 0x06:
current_cmd = SPIFlashSymbol::CMD_WRITE_ENABLE;
state = STATE_IDLE;
break;

//Read the status register
//TODO: this is W25N specific, normal NOR flash jumps right into the data
//TODO: address is is W25N specific, normal NOR flash jumps right into the data
//(need enum parameters!!!)
case 0x0f:
case 0x5f:
@@ -211,17 +242,17 @@ void SPIFlashDecoder::Refresh()
addr_start = din->m_offsets[iin+1];
break;

//Write the status register
//TODO: W25N specific
case 0x01:
case 0x1f:
current_cmd = SPIFlashSymbol::CMD_WRITE_STATUS_REGISTER;
//Quad input page program
case 0x32:
current_cmd = SPIFlashSymbol::CMD_QUAD_PAGE_PROGRAM;
state = STATE_ADDRESS;
address_bytes_left = 1;
address_bytes_left = 2; //TODO: this is device specific, current value is for W25N
addr = 0;
addr_start = din->m_offsets[iin+1];
break;

//0x3b 1-1-2 fast read

//1-1-4 fast read
case 0x6b:
current_cmd = SPIFlashSymbol::CMD_READ_1_1_4;
@@ -231,6 +262,25 @@ void SPIFlashDecoder::Refresh()
addr_start = din->m_offsets[iin+1];
break;

//Read the IDCODE
case 0x9f:
current_cmd = SPIFlashSymbol::CMD_READ_JEDEC_ID;
state = STATE_DUMMY_BEFORE_DATA;
data_type = SPIFlashSymbol::TYPE_VENDOR_ID;
break;

//0xbb 1-2-2 fast read

//Erase a block (size is device dependent)
//Commonly 64 or 128 Kbytes
case 0xd8:
current_cmd = SPIFlashSymbol::CMD_BLOCK_ERASE;
state = STATE_ADDRESS;
address_bytes_left = 2; //TODO: this is device specific, current value is for W25N
addr = 0;
addr_start = din->m_offsets[iin+1];
break;

//1-4-4 fast read
case 0xeb:
current_cmd = SPIFlashSymbol::CMD_READ_1_4_4;
@@ -240,18 +290,23 @@ void SPIFlashDecoder::Refresh()
addr_start = din->m_offsets[iin+1];
break;

//Slow read (no dummy clocks)
case 0x03:
current_cmd = SPIFlashSymbol::CMD_READ;
state = STATE_ADDRESS;
address_bytes_left = 2; //TODO: this is device specific, current value is for W25N
addr = 0;
addr_start = din->m_offsets[iin+1];
//Reset should occur by itself, ignore any data after that
case 0xff:
current_cmd = SPIFlashSymbol::CMD_RESET;
state = STATE_IDLE;
break;

////////////////////////////////////////////////////////////////////////////////////////////////
// Winbond W25N specific below here

//Execute the program operation
case 0x10:
current_cmd = SPIFlashSymbol::CMD_W25N_PROGRAM_EXECUTE;
state = STATE_DUMMY_BEFORE_ADDRESS;
address_bytes_left = 2;
addr = 0;
break;

//Read a page of NAND
case 0x13:
current_cmd = SPIFlashSymbol::CMD_W25N_READ_PAGE;
@@ -260,6 +315,17 @@ void SPIFlashDecoder::Refresh()
addr = 0;
break;

//0x0c fast read with 4 byte address
//0x34 quad random load program data
//0x3c fast read dual with 4 byte address
//0x6c fast read quad with 4 byte address
//0x84 random load program data
//0xA1 write bad block table
//0xA5 read bad block table
//0xA9 read last ECC failure address
//0xBC fast read dual i/o with 4 byte address
//0xEC fast read quad i/o with 4 byte address

//Drop unknown commands
default:
current_cmd = SPIFlashSymbol::CMD_UNKNOWN;
@@ -311,7 +377,7 @@ void SPIFlashDecoder::Refresh()
{
case SPIFlashSymbol::CMD_READ_1_1_4:
case SPIFlashSymbol::CMD_READ_1_4_4:
state = STATE_READ_QUAD_DATA;
state = STATE_QUAD_DATA;
break;
default:
state = STATE_READ_DATA;
@@ -323,9 +389,44 @@ void SPIFlashDecoder::Refresh()

//Read address in QSPI mode
case STATE_QUAD_ADDRESS:
//TODO
if(s.m_stype != SPISymbol::TYPE_DATA)
state = STATE_IDLE;

//Discard quad samples until we're lined up with the start of the x1 sample
while(iquad < quadlen)
{
if(dquad->m_offsets[iquad] >= din->m_offsets[iin])
break;
iquad ++;
}

//Read quad samples until we finish the address
while( (iquad < quadlen) && (address_bytes_left > 0) )
{
auto squad = dquad->m_samples[iquad];
if(squad.m_stype != SPISymbol::TYPE_DATA)
break;

//Save the address byte
addr = (addr << 8) | squad.m_data;
address_bytes_left --;

iquad ++;
}

//Add the address
cap->m_offsets.push_back(addr_start);
cap->m_durations.push_back(dquad->m_offsets[iquad] + dquad->m_durations[iquad] - addr_start);
cap->m_samples.push_back(SPIFlashSymbol(
SPIFlashSymbol::TYPE_ADDRESS, SPIFlashSymbol::CMD_UNKNOWN, addr));

{
char tmp[128] = "";
snprintf(tmp, sizeof(tmp), "%x", addr);
pack->m_headers["Address"] = tmp;
}

state = STATE_QUAD_DATA;
data_type = SPIFlashSymbol::TYPE_DATA;

break;

//Read address in SPI mode
@@ -353,6 +454,10 @@ void SPIFlashDecoder::Refresh()
state = STATE_DUMMY_BEFORE_DATA;
break;

case SPIFlashSymbol::CMD_FAST_READ:
state = STATE_DUMMY_BEFORE_DATA;
break;

//If we're accessing the status register, check the address
//TODO: W25N specific
case SPIFlashSymbol::CMD_READ_STATUS_REGISTER:
@@ -382,6 +487,16 @@ void SPIFlashDecoder::Refresh()
state = STATE_DUMMY_BEFORE_DATA;
break;

//Writing a page
case SPIFlashSymbol::CMD_PAGE_PROGRAM:
state = STATE_WRITE_DATA;
break;

//Writing a page in x4 mode
case SPIFlashSymbol::CMD_QUAD_PAGE_PROGRAM:
state = STATE_QUAD_DATA;
break;

default:
break;
}
@@ -466,8 +581,8 @@ void SPIFlashDecoder::Refresh()

break; //STATE_READ_DATA

//Read data in quad mode
case STATE_READ_QUAD_DATA:
//Read or write data in quad mode
case STATE_QUAD_DATA:

//Discard quad samples until we're lined up with the start of the x1 sample
while(iquad < quadlen)
@@ -616,10 +731,12 @@ string SPIFlashDecoder::GetText(int i)
{
case SPIFlashSymbol::CMD_READ:
return "Read";
case SPIFlashSymbol::CMD_FAST_READ:
return "Read Fast";
case SPIFlashSymbol::CMD_READ_1_1_4:
return "Quad Read";
return "Read Quad";
case SPIFlashSymbol::CMD_READ_1_4_4:
return "Quad I/O Read";
return "Read Quad I/O";
case SPIFlashSymbol::CMD_READ_JEDEC_ID:
return "Read JEDEC ID";
case SPIFlashSymbol::CMD_READ_STATUS_REGISTER:
@@ -628,6 +745,18 @@ string SPIFlashDecoder::GetText(int i)
return "Write Status";
case SPIFlashSymbol::CMD_RESET:
return "Reset";
case SPIFlashSymbol::CMD_WRITE_DISABLE:
return "Write Disable";
case SPIFlashSymbol::CMD_WRITE_ENABLE:
return "Write Enable";
case SPIFlashSymbol::CMD_BLOCK_ERASE:
return "Block Erase";
case SPIFlashSymbol::CMD_PAGE_PROGRAM:
return "Page Program";

//W25N specific
case SPIFlashSymbol::CMD_W25N_PROGRAM_EXECUTE:
return "Program Execute";
case SPIFlashSymbol::CMD_W25N_READ_PAGE:
return "Read Page";

@@ -812,3 +941,28 @@ string SPIFlashDecoder::GetPartID(SPIFlashWaveform* cap, const SPIFlashSymbol& s
return tmp;
}
}

bool SPIFlashDecoder::CanMerge(Packet* a, Packet* b)
{
//Merge read-status packets
if( (a->m_headers["Op"] == "Read Status") && (b->m_headers["Op"] == "Read Status") )
return true;

return false;
}

Packet* SPIFlashDecoder::CreateMergedHeader(Packet* pack)
{
if(pack->m_headers["Op"] == "Read Status")
{
Packet* ret = new Packet;
ret->m_offset = pack->m_offset;
ret->m_len = pack->m_len; //TODO: extend?
ret->m_headers["Op"] = "Poll Status";

//TODO: add other fields?
return ret;
}

return NULL;
}
10 changes: 10 additions & 0 deletions scopeprotocols/SPIFlashDecoder.h
Original file line number Diff line number Diff line change
@@ -69,12 +69,19 @@ class SPIFlashSymbol
CMD_WRITE_STATUS_REGISTER,
CMD_READ_JEDEC_ID,
CMD_READ, //Read, SPI address, SPI data
CMD_FAST_READ, //Fast read, SPI mode, with pipeline delay
CMD_READ_1_1_4, //Fast read, SPI address, QSPI data
CMD_READ_1_4_4, //Fast read, QSPI address, QSPI data
CMD_RESET,
CMD_WRITE_ENABLE,
CMD_WRITE_DISABLE,
CMD_BLOCK_ERASE,
CMD_PAGE_PROGRAM,
CMD_QUAD_PAGE_PROGRAM,

//Winbond W25N specific
CMD_W25N_READ_PAGE,
CMD_W25N_PROGRAM_EXECUTE,

CMD_UNKNOWN
} m_cmd;
@@ -125,6 +132,9 @@ class SPIFlashDecoder : public PacketDecoder
VENDOR_ID_WINBOND = 0xef
};

virtual bool CanMerge(Packet* a, Packet* b);
virtual Packet* CreateMergedHeader(Packet* pack);

PROTOCOL_DECODER_INITPROC(SPIFlashDecoder)

protected: