Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A bug of MemTool in GUI that can be fixed (and some script engine issues) #23

Open
wuwbobo2021 opened this issue Oct 14, 2024 · 6 comments

Comments

@wuwbobo2021
Copy link

Please fix the problem that prevents MemTool from handling the external memory chip connected to a device that have an non-zero index in the current JTAG chain:

https://github.com/viveris/jtag-boundary-scanner/blob/d2b44e81b3eaaa18b899af9c9f631dd70dce9d67/jtag_boundary_scanner_gui/win32/JTAGBoundaryScanner.c

In JTAGBoundaryScanner.c, set_mem_pins(), at lines 1974 and 2005, change

pin_id = jtagcore_get_pin_id(jc, 0, ptr);

to

pin_id = jtagcore_get_pin_id(jc, last_selected_dev_index, ptr);

However, the GUI is still incapable of controlling a flash memory through 2 devices in the JTAG chain.

@wuwbobo2021
Copy link
Author

Another interesting problem: a script file saved by the text editor in Linux (Unix LF) cannot be executed correctly by the script engine on Windows. I don't know how to fix it in function execute_file_script(), but copied the text to another Notepad on Windows and saved it.

@jfdelnero
Copy link
Member

Another interesting problem: a script file saved by the text editor in Linux (Unix LF) cannot be executed correctly by the script engine on Windows. I don't know how to fix it in function execute_file_script(), but copied the text to another Notepad on Windows and saved it.

both linux and windows line returns are supported. I think that this is more an utf8 compatibility issue.

@wuwbobo2021
Copy link
Author

wuwbobo2021 commented Oct 15, 2024

Important note: why don't warn people about the read/write size limitation determined by DEFAULT_BUFLEN in the code?

I found a problem in the script engine: jtag_set_pin_state command cannot set the pin out value according to a variable. It might be fixed in cmd_set_pin_state() by calling getEnvVarDat() as it does in cmd_print().

However, I'm unfamiliar with the structure of this project (written in C89 style, lacking documentation), and decided not to patch it by myself. I switched to pyjtagbs: colinoflynn/pyjtagbs#8.

I'm trying to execute custom commands for the flash memory (vendor-specific features / hidden sector, TopJTAG Flash can't do it) through 2 devices in the JTAG chain. Here's my test script merely reading Flash CFI information (by single JTAG device), but it doesn't work correctly because of the behavior described above.

PS: when the script below is saved in Unix LF mode, the executor (on Windows) reports something like Command not found ! : TEMP = $TEMP & 1, Command not found ! : dir $DEV_INDEX md(3) 0, as if a few lines are broken in the middle. I saved some simpler script in LF mode and it works. And no non-ASCII character is found in this script.

# PXA255  AM29LV160D

bs_test:

jtag_get_probes_list
jtag_open_probe 0x00000100
jtag_init_scan
jtag_get_devices_list
jtag_load_bsdl C:\Downloads\mt506s\pxa255.bsd 0
jtag_set_mode 0 EXTEST

$DEV_INDEX = 0
jtag_set_pin_dir $DEV_INDEX noe 1
jtag_set_pin_dir $DEV_INDEX nwe 1
jtag_set_pin_dir $DEV_INDEX ncs_0 1
call . set_addr_oe

$ADDR = 0x0055
$WORD_WRITE = 0x0098
call . write

$ADDR = 0x10
call . read
print CFI DATA 0: $WORD_READ

$ADDR = 0x11
call . read
print CFI DATA 1: $WORD_READ

$ADDR = 0x12
call . read
print CFI DATA 2: $WORD_READ

return

# Write -----------------------------------------------------------------
# Params $ADDR $WORD_WRITE -> ()
write:
call . write_addr
call . set_data_oe
call . write_word
# assumes CTRL_RD, CTRL_WR, CTRL_CS are all disabled here (output 1)
jtag_push_pop
jtag_set_pin_state $DEV_INDEX ncs_0 0
jtag_set_pin_state $DEV_INDEX nwe 0
jtag_push_pop
jtag_set_pin_state $DEV_INDEX nwe 1
jtag_push_pop
jtag_set_pin_state $DEV_INDEX ncs_0 1
call . reset_data_oe
jtag_push_pop

return

# Read ------------------------------------------------------------------
# Param $ADDR -> $WORD_READ
read:
call . write_addr
call . reset_data_oe
# assumes CTRL_RD, CTRL_WR, CTRL_CS are all disabled here (output 1)
jtag_push_pop
jtag_set_pin_state $DEV_INDEX ncs_0 0
jtag_push_pop
jtag_set_pin_state $DEV_INDEX noe 0
jtag_push_pop
jtag_push_pop
call . read_word
jtag_set_pin_state $DEV_INDEX noe 1
jtag_set_pin_state $DEV_INDEX ncs_0 1
jtag_push_pop

return

# -----------------------------------------------------------------------
set_addr_oe:

jtag_set_pin_dir $DEV_INDEX ma(1) 1
jtag_set_pin_dir $DEV_INDEX ma(2) 1
jtag_set_pin_dir $DEV_INDEX ma(3) 1
jtag_set_pin_dir $DEV_INDEX ma(4) 1
jtag_set_pin_dir $DEV_INDEX ma(5) 1
jtag_set_pin_dir $DEV_INDEX ma(6) 1
jtag_set_pin_dir $DEV_INDEX ma(7) 1
jtag_set_pin_dir $DEV_INDEX ma(8) 1
jtag_set_pin_dir $DEV_INDEX ma(9) 1
jtag_set_pin_dir $DEV_INDEX ma(10) 1
jtag_set_pin_dir $DEV_INDEX ma(11) 1
jtag_set_pin_dir $DEV_INDEX ma(12) 1
jtag_set_pin_dir $DEV_INDEX ma(13) 1
jtag_set_pin_dir $DEV_INDEX ma(14) 1
jtag_set_pin_dir $DEV_INDEX ma(15) 1
jtag_set_pin_dir $DEV_INDEX ma(16) 1
jtag_set_pin_dir $DEV_INDEX ma(17) 1
jtag_set_pin_dir $DEV_INDEX ma(18) 1
jtag_set_pin_dir $DEV_INDEX ma(19) 1
jtag_set_pin_dir $DEV_INDEX ma(20) 1
jtag_set_pin_dir $DEV_INDEX ma(21) 1

return

# -----------------------------------------------------------------------
set_data_oe:

jtag_set_pin_dir $DEV_INDEX md(0) 1
jtag_set_pin_dir $DEV_INDEX md(1) 1
jtag_set_pin_dir $DEV_INDEX md(2) 1
jtag_set_pin_dir $DEV_INDEX md(3) 1
jtag_set_pin_dir $DEV_INDEX md(4) 1
jtag_set_pin_dir $DEV_INDEX md(5) 1
jtag_set_pin_dir $DEV_INDEX md(6) 1
jtag_set_pin_dir $DEV_INDEX md(7) 1
jtag_set_pin_dir $DEV_INDEX md(8) 1
jtag_set_pin_dir $DEV_INDEX md(9) 1
jtag_set_pin_dir $DEV_INDEX md(10) 1
jtag_set_pin_dir $DEV_INDEX md(11) 1
jtag_set_pin_dir $DEV_INDEX md(12) 1
jtag_set_pin_dir $DEV_INDEX md(13) 1
jtag_set_pin_dir $DEV_INDEX md(14) 1
jtag_set_pin_dir $DEV_INDEX md(15) 1

return

# -----------------------------------------------------------------------
reset_data_oe:

jtag_set_pin_dir $DEV_INDEX md(0) 0
jtag_set_pin_dir $DEV_INDEX md(1) 0
jtag_set_pin_dir $DEV_INDEX md(2) 0
jtag_set_pin_dir $DEV_INDEX md(3) 0
jtag_set_pin_dir $DEV_INDEX md(4) 0
jtag_set_pin_dir $DEV_INDEX md(5) 0
jtag_set_pin_dir $DEV_INDEX md(6) 0
jtag_set_pin_dir $DEV_INDEX md(7) 0
jtag_set_pin_dir $DEV_INDEX md(8) 0
jtag_set_pin_dir $DEV_INDEX md(9) 0
jtag_set_pin_dir $DEV_INDEX md(10) 0
jtag_set_pin_dir $DEV_INDEX md(11) 0
jtag_set_pin_dir $DEV_INDEX md(12) 0
jtag_set_pin_dir $DEV_INDEX md(13) 0
jtag_set_pin_dir $DEV_INDEX md(14) 0
jtag_set_pin_dir $DEV_INDEX md(15) 0

return

# -----------------------------------------------------------------------
write_addr:

# Params: $DEV_INDEX  $ADDR

print write_addr( $ADDR ) entered

$TEMP = $ADDR >> 0
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(1) $TEMP

$TEMP = $ADDR >> 1
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(2) $TEMP

$TEMP = $ADDR >> 2
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(3) $TEMP

$TEMP = $ADDR >> 3
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(4) $TEMP

$TEMP = $ADDR >> 4
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(5) $TEMP

$TEMP = $ADDR >> 5
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(6) $TEMP

$TEMP = $ADDR >> 6
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(7) $TEMP

$TEMP = $ADDR >> 7
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(8) $TEMP

$TEMP = $ADDR >> 8
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(9) $TEMP

$TEMP = $ADDR >> 9
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(10) $TEMP

$TEMP = $ADDR >> 10
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(11) $TEMP

$TEMP = $ADDR >> 11
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(12) $TEMP

$TEMP = $ADDR >> 12
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(13) $TEMP

$TEMP = $ADDR >> 13
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(14) $TEMP

$TEMP = $ADDR >> 14
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(15) $TEMP

$TEMP = $ADDR >> 15
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(16) $TEMP

$TEMP = $ADDR >> 16
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(17) $TEMP

$TEMP = $ADDR >> 17
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(18) $TEMP

$TEMP = $ADDR >> 18
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(19) $TEMP

$TEMP = $ADDR >> 19
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(20) $TEMP

$TEMP = $ADDR >> 20
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX ma(21) $TEMP

return

# -----------------------------------------------------------------------
read_word:

# Params: $DEV_INDEX
# Sets: $WORD_READ 
$WORD_READ = 0

jtag_get_pin_state 0 md(0) 0
$TEMP = $LASTDATA << 0
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(1) 0
$TEMP = $LASTDATA << 1
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(2) 0
$TEMP = $LASTDATA << 2
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(3) 0
$TEMP = $LASTDATA << 3
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(4) 0
$TEMP = $LASTDATA << 4
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(5) 0
$TEMP = $LASTDATA << 5
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(6) 0
$TEMP = $LASTDATA << 6
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(7) 0
$TEMP = $LASTDATA << 7
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(8) 0
$TEMP = $LASTDATA << 8
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(9) 0
$TEMP = $LASTDATA << 9
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(10) 0
$TEMP = $LASTDATA << 10
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(11) 0
$TEMP = $LASTDATA << 11
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(12) 0
$TEMP = $LASTDATA << 12
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(13) 0
$TEMP = $LASTDATA << 13
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(14) 0
$TEMP = $LASTDATA << 14
$WORD_READ = $WORD_READ | $TEMP

jtag_get_pin_state 0 md(15) 0
$TEMP = $LASTDATA << 15
$WORD_READ = $WORD_READ | $TEMP

return

# -----------------------------------------------------------------------
write_word:

# Params: $DEV_INDEX  $WORD_WRITE

$TEMP = $WORD_WRITE >> 0
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(0) $TEMP

$TEMP = $WORD_WRITE >> 1
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(1) $TEMP

$TEMP = $WORD_WRITE >> 2
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(2) $TEMP

$TEMP = $WORD_WRITE >> 3
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(3) $TEMP

$TEMP = $WORD_WRITE >> 4
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(4) $TEMP

$TEMP = $WORD_WRITE >> 5
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(5) $TEMP

$TEMP = $WORD_WRITE >> 6
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(6) $TEMP

$TEMP = $WORD_WRITE >> 7
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(7) $TEMP

$TEMP = $WORD_WRITE >> 8
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(8) $TEMP

$TEMP = $WORD_WRITE >> 9
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(9) $TEMP

$TEMP = $WORD_WRITE >> 10
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(10) $TEMP

$TEMP = $WORD_WRITE >> 11
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(11) $TEMP

$TEMP = $WORD_WRITE >> 12
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(12) $TEMP

$TEMP = $WORD_WRITE >> 13
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(13) $TEMP

$TEMP = $WORD_WRITE >> 14
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(14) $TEMP

$TEMP = $WORD_WRITE >> 15
$TEMP = $TEMP & 1
jtag_set_pin_state $DEV_INDEX md(15) $TEMP

return

@wuwbobo2021 wuwbobo2021 changed the title A bug of MemTool in GUI that can be fixed A bug of MemTool in GUI that can be fixed (and some script engine issues) Oct 15, 2024
@wuwbobo2021
Copy link
Author

wuwbobo2021 commented Oct 15, 2024

pyjtagbs equivalent of the above script:

from jtagbs import jtagbs
from jtagbs.viveris import jtagcore

# Memory read/write procedures were translated from `memoryoverjtag.c` in libjtagcore

# Requires `jtag`, `device`, `addr_pins`, `data_pins`, `cs_pin`, `we_pin`, `oe_pin`
def mem_write(addr, data):
    par_set_data(device, addr_pins, addr)
    par_set_data(device, data_pins, data) # sets OE for data pins
    # assumes all control signals are disabled here (Output 1)
    jtag.scan()
    device.set_pin_state(cs_pin, 0) # enable CS
    device.set_pin_state(we_pin, 0) # enable WE
    jtag.scan()
    device.set_pin_state(we_pin, 1) # disable WE
    jtag.scan()
    device.set_pin_state(cs_pin, 1) # disable CS
    par_reset_oe(device, data_pins)
    jtag.scan()

# Requires `jtag`, `device`, `addr_pins`, `data_pins`, `cs_pin`, `we_pin`, `oe_pin`
def mem_read(addr):
    par_set_data(device, addr_pins, addr)
    par_reset_oe(device, data_pins)
    # assumes all control signals are disabled here (Output 1)
    jtag.scan()
    device.set_pin_state(cs_pin, 0) # enable CS
    jtag.scan()
    device.set_pin_state(oe_pin, 0) # enable OE
    jtag.scan()
    jtag.scan()
    data = par_get_data(device, data_pins)
    device.set_pin_state(oe_pin, 1) # disable OE
    device.set_pin_state(cs_pin, 1) # disable CS
    jtag.scan()
    return data

def par_get_data(device, pins):
    pin_states = device.get_pin_state(pins)
    data = 0
    for i, val in enumerate(pin_states):
        data += (val << i)
    return data

def par_set_data(device, pins, data):
    new_states = []
    for i in range(len(pins)):
        new_states.append((data >> i) & 1) # 1 => True, 0 => False
    device.set_pin_state(pins, new_states) # sets OE for pins

def par_reset_oe(device, pins):
    device.set_pin_state(pins, list(None for i in range(len(pins)))) # disables OE
    
# main --------------------------------------------------------------

if __name__ == '__main__':
    interface = jtagcore.JTAGCore()
    jtag = jtagbs.JTAGBS(interface)

    probes = jtag.list_available_probes()
    jtag.open_probe('JLINK')
    jtag.init_scanchain()

    devices = jtag.list_devices()
    for i, dev in enumerate(devices):
        print("Device {} is from {}".format(i, dev['manufacturer']))

    pxa255 = jtag.get_device(0)
    pxa255.set_bsdl(r"../bsdl_files/pxa255.bsd")

    addr_pins = ['ma(1)', 'ma(2)', 'ma(3)', 'ma(4)', 'ma(5)', \
                 'ma(6)', 'ma(7)', 'ma(8)', 'ma(9)', 'ma(10)', \
                 'ma(11)', 'ma(12)', 'ma(13)', 'ma(14)', 'ma(15)', \
                 'ma(16)', 'ma(17)', 'ma(18)', 'ma(19)', 'ma(20)', 'ma(21)']
    data_pins = ['md(0)', 'md(1)', 'md(2)', 'md(3)', 'md(4)', 'md(5)', 'md(6)', 'md(7)', \
                 'md(8)', 'md(9)', 'md(10)', 'md(11)', 'md(12)', 'md(13)', 'md(14)', 'md(15)']

    cs_pin, we_pin, oe_pin = ('ncs_0', 'nwe', 'noe')

    pxa255.set_scan_mode('active') # EXTEST
    pxa255.autoscan = False # call `JTAGBS.scan()` to update inputs and outputs

    device = pxa255

    # sets OE for control pins, disables control siginals
    pxa255.set_pin_state([cs_pin, we_pin, oe_pin], [True, True, True]) 
    jtag.scan()

    mem_write(0x55, 0x0098)

    cfi_data = bytearray()
    for i in range(0x10, 0x4C + 1):
        word_read = mem_read(i)
        cfi_data.append(word_read & 0xff)

    print(cfi_data)

@jfdelnero
Copy link
Member

In JTAGBoundaryScanner.c, set_mem_pins(), at lines 1974 and 2005, change

Fixed in the v2.6.6.1

Important note: why don't warn people about the read/write size limitation determined by DEFAULT_BUFLEN in the code?

This is the script max length per line, currently set to 1024. Can you tell which use case need more than this ?

I found a problem in the script engine: jtag_set_pin_state command cannot set the pin out value according to a variable. It might >be fixed in cmd_set_pin_state() by calling getEnvVarDat() as it does in cmd_print().

This is fixed in the v2.6.6.1. The issue was related to the use of "atoi" function to convert numbers while the internal string numbers are in hexadecimal.

PS: when the script below is saved in Unix LF mode, the executor (on Windows) reports something like Command not found ! : >TEMP = $TEMP & 1, Command not found ! : dir $DEV_INDEX md(3) 0, as if a few lines are broken in the middle. I saved some >simpler script in LF mode and it works. And no non-ASCII character is found in this script.

I still suspect an utf8 compatibility issue. Can you share the script file ?

@wuwbobo2021
Copy link
Author

Thanks for fixing both bugs. And I realized that I had got something wrong: variables are handled by get_param(), not by cmd_set_pin_state() itself, that's not a clue for solving the problem.

My script usage is already posted here, but I have already switched to pyjtagbs.

DEFAULT_BUFLEN size limitation is not only related to scripting issues: it affects some tools in the GUI as well, including MemTool. And I had read data fron the 24LC64 EEPROM via I2C Tool provided here, but I had to split it into read operations of 256B.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants