From 3a1ec19c8cced064ea473c230e8dc38fa25b3966 Mon Sep 17 00:00:00 2001 From: Kolja Waschk Date: Sat, 19 Jan 2008 21:25:46 +0000 Subject: [PATCH] Actual implementation of cable driver for JIM, basic TAP state machine, and a skeleton for "some_cpu" with working IDCODE detection. git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@932 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/ChangeLog | 4 +- jtag/include/jim.h | 102 +++++++++++++ jtag/include/jim/some_cpu.h | 29 ++++ jtag/src/jim/Makefile.am | 3 +- jtag/src/jim/some_cpu.c | 73 +++++++++ jtag/src/jim/tap.c | 288 ++++++++++++++++++++++++++++++++++++ jtag/src/tap/cable/jim.c | 60 +++++++- 7 files changed, 553 insertions(+), 6 deletions(-) create mode 100644 jtag/include/jim.h create mode 100644 jtag/include/jim/some_cpu.h create mode 100644 jtag/src/jim/some_cpu.c diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 6ad48c64..40a45396 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -2,7 +2,9 @@ * ChangeLog: whitespace cosmetics * Makefile.am, configure.ac, jim/tap.c, jim/Makefile.am, jim/README.jim, - tap/cable/jim.c, tap/cable.c, tap/Makefile.am: JTAG target sim skeleton + tap/cable/jim.c, tap/cable.c, tap/Makefile.am, jim/some_cpu.c, + include/jim.h, include/jim/some_cpu.h: JTAG target simulator "JIM" + and a "jim" cable driver to "connect" to it; detection already works. 2008-01-18 Arnim Laeuger diff --git a/jtag/include/jim.h b/jtag/include/jim.h new file mode 100644 index 00000000..8257c823 --- /dev/null +++ b/jtag/include/jim.h @@ -0,0 +1,102 @@ +/* + * $Id: jim.h $ + * + * Copyright (C) 2008 Kolja Waschk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Documentation used while writing this code: + * + * http://www.inaccessnetworks.com/projects/ianjtag/jtag-intro/jtag-intro.html + * "A Brief Introduction to the JTAG Boundary Scan Interface", Nick Patavalis + * + * http://www.xjtag.com/support-jtag/jtag-technical-guide.php + * "JTAG - A technical overview", XJTAG Ltd. + * + */ + +#ifndef JIM_H +#define JIM_H 1 + +#include + +typedef enum +{ + RESET = 0, + SELECT_DR = 0+1, + CAPTURE_DR = 0+2, + SHIFT_DR = 0+3, + EXIT1_DR = 0+4, + PAUSE_DR = 0+5, + EXIT2_DR = 0+6, + UPDATE_DR = 0+7, + IDLE = 8, + SELECT_IR = 8+1, + CAPTURE_IR = 8+2, + SHIFT_IR = 8+3, + EXIT1_IR = 8+4, + PAUSE_IR = 8+5, + EXIT2_IR = 8+6, + UPDATE_IR = 8+7, +} +tap_state_t; + +typedef struct +{ + uint32_t *reg; + int len; +} shift_reg_t; + +typedef struct jim_device +{ + struct jim_device *prev; + + tap_state_t tap_state; + void (*tck_rise)(struct jim_device *dev, int tms, int tdi); + void (*tck_fall)(struct jim_device *dev); + void (*dev_free)(struct jim_device *dev); + int num_sregs; + int current_dr; + shift_reg_t *sreg; + int tdo; + int tdo_buffer; +} +jim_device_t; + +typedef struct jim_state +{ + int trst; + jim_device_t *last_device_in_chain; +} +jim_state_t; + + +void jim_set_trst(jim_state_t *s, int trst); +int jim_get_trst(jim_state_t *s); +int jim_get_tdo(jim_state_t *s); +void jim_tck_rise(jim_state_t *s, int tms, int tdi); +void jim_tck_fall(jim_state_t *s); +jim_device_t *jim_alloc_device(int num_sregs, const int reg_size[]); +jim_state_t *jim_init(void); +void jim_free(jim_state_t *s); +void jim_print_sreg(shift_reg_t *r); +void jim_print_tap_state(jim_device_t *dev); + +#endif + diff --git a/jtag/include/jim/some_cpu.h b/jtag/include/jim/some_cpu.h new file mode 100644 index 00000000..1fd50ab7 --- /dev/null +++ b/jtag/include/jim/some_cpu.h @@ -0,0 +1,29 @@ +/* + * $Id: tap.c $ + * + * Copyright (C) 2008 Kolja Waschk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +void some_cpu_tck_rise(jim_device_t *dev); +jim_device_t *some_cpu(void); + diff --git a/jtag/src/jim/Makefile.am b/jtag/src/jim/Makefile.am index 975904c4..60bbeba6 100644 --- a/jtag/src/jim/Makefile.am +++ b/jtag/src/jim/Makefile.am @@ -26,4 +26,5 @@ include $(top_srcdir)/Makefile.rules noinst_LIBRARIES = libjim.a libjim_a_SOURCES = \ - tap.c + tap.c \ + some_cpu.c diff --git a/jtag/src/jim/some_cpu.c b/jtag/src/jim/some_cpu.c new file mode 100644 index 00000000..802be1f1 --- /dev/null +++ b/jtag/src/jim/some_cpu.c @@ -0,0 +1,73 @@ +/* + * $Id: tap.c $ + * + * Copyright (C) 2008 Kolja Waschk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +void some_cpu_tck_rise(jim_device_t *dev, int tms, int tdi) +{ + // jim_print_tap_state(dev); + + switch(dev->tap_state) + { + case RESET: + dev->sreg[0].reg[0] = 0x1; /* IDCODE instruction 0001 */ + dev->sreg[1].reg[0] = 0x87654321; /* Load IDR (fake) */ + dev->current_dr = 1; /* IDR */ + break; + + case UPDATE_IR: + switch(dev->sreg[0].reg[0]) + { + case 0x1: /* IDCODE */ + dev->sreg[1].reg[0] = 0x87654321; /* Load IDR (fake) */ + dev->current_dr = 1; /* IDR */ + break; + case 0xF: /* BYPASS */ + default: + dev->current_dr = 0; /* BYPASS */ + break; + } + break; + + default: + break; + } +} + +jim_device_t *some_cpu(void) +{ + jim_device_t *dev; + const int reg_size[2] = { 4 /* IR */, 32 /* IDR */ }; + + dev = jim_alloc_device(2, reg_size); + + if(dev) + { + dev->tck_rise = some_cpu_tck_rise; + } + + return dev; +} + diff --git a/jtag/src/jim/tap.c b/jtag/src/jim/tap.c index e69de29b..17a95702 100644 --- a/jtag/src/jim/tap.c +++ b/jtag/src/jim/tap.c @@ -0,0 +1,288 @@ +/* + * $Id: tap.c $ + * + * Copyright (C) 2008 Kolja Waschk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +const tap_state_t next_tap_state[16][2] = +{ + /* RESET */ { IDLE, RESET }, + /* SELECT_DR */ { CAPTURE_DR, SELECT_IR }, + /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR }, + /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR }, + /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR }, + /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR }, + /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR }, + /* UPDATE_DR */ { IDLE, SELECT_DR }, + /* IDLE */ { IDLE, SELECT_DR }, + /* SELECT_IR */ { CAPTURE_IR, RESET }, + /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR }, + /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR }, + /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR }, + /* PAUSE_IR */ { EXIT2_IR, EXIT2_IR }, + /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR }, + /* UPDATE_IR */ { IDLE, SELECT_DR } +}; + +void jim_print_sreg(shift_reg_t *r) +{ + printf("%08X", r->reg[0]); +} + +void jim_print_tap_state(jim_device_t *dev) +{ + printf(" tck rise, state="); + switch(dev->tap_state & 7) + { + case 0: printf((dev->tap_state==RESET) ? "RESET":"IDLE" ); break; + case 1: printf("SELECT"); break; + case 2: printf("CAPTURE"); break; + case 3: printf("SHIFT"); break; + case 4: printf("EXIT1"); break; + case 5: printf("PAUSE"); break; + case 6: printf("EXIT2"); break; + default: printf("UPDATE"); break; + }; + if(dev->tap_state & 7) + { + if(dev->tap_state & 8) + { + printf("_IR="); jim_print_sreg(&dev->sreg[0]); + } + else + { + printf("_DR"); + if(dev->current_dr != 0) + { + printf("="); + jim_print_sreg(&dev->sreg[dev->current_dr]); + } + }; + }; + printf("\n"); +} + + +void jim_set_trst(jim_state_t *s, int trst) +{ + s->trst = trst; +} + +int jim_get_trst(jim_state_t *s) +{ + return s->trst; +} + +int jim_get_tdo(jim_state_t *s) +{ + if(s->last_device_in_chain == NULL) return 0; + return s->last_device_in_chain -> tdo; +} + +void jim_tck_rise(jim_state_t *s, int tms, int tdi) +{ + jim_device_t *dev; + + for(dev = s->last_device_in_chain; dev; dev = dev->prev) + { + int dev_tdi; + int i, n; + shift_reg_t *sr; + uint32_t *reg; + + dev_tdi = (dev->prev != NULL) ? dev->prev->tdo : tdi; + + if(dev->tck_rise != NULL) dev->tck_rise(dev, tms, dev_tdi); + + if(dev->tap_state & 8) + { + sr = &(dev->sreg[0]); + } + else + { + if(dev->current_dr == 0) + { + sr = NULL; /* BYPASS */ + } + else + { + sr = &(dev->sreg[dev->current_dr]); + } + } + + if(sr == NULL) /* BYPASS */ + { + dev->tdo_buffer = dev_tdi; + } + else + { + reg = sr->reg; + + if(dev->tap_state == SHIFT_IR || dev->tap_state == SHIFT_DR) + { + /* Start with LSW of shift register at index 0 */ + + n = (sr->len-1) / 32; + for(i=0; i < (sr->len-1)/32; i++) + { + reg[i] >>= 1; + if(reg[i+1] & 1) reg[i] |= 0x8000; + }; + + /* End with MSW at index i */ + + reg[i] >>=1; + if(dev_tdi != 0) + { + n = (sr->len & 31); + if(n == 0) n = 32; + reg[i] |= (1 << (n-1)); + } + } + + dev->tdo_buffer = reg[0] & 1; + } + + dev->tap_state = next_tap_state[dev->tap_state][tms]; + } +} + +void jim_tck_fall(jim_state_t *s) +{ + jim_device_t *dev; + + for(dev = s->last_device_in_chain; dev; dev = dev->prev) + { + dev->tdo = dev->tdo_buffer; + + if(dev->tck_fall != NULL) dev->tck_fall(dev); + } +} + +jim_device_t *jim_alloc_device(int num_sregs, const int reg_size[]) +{ + int i, r; + + jim_device_t *dev = (jim_device_t *)malloc(sizeof(jim_device_t)); + + if(dev == NULL) + { + printf("Out of memory\n"); + return NULL; + } + + dev->sreg = + (shift_reg_t *)malloc(num_sregs * sizeof(shift_reg_t)); + + if(dev->sreg == NULL) + { + free(dev); + printf("Out of memory\n"); + return NULL; + } + + for(r=0,i=0;isreg[i].len = reg_size[i]; + dev->sreg[i].reg = + (uint32_t*)calloc(((reg_size[i]+31)/32), sizeof(uint32_t)); + if(dev->sreg[i].reg == NULL) r++; + } + + if(r>0) + { + printf("Out of memory\n"); + for(i=0;isreg[i].reg!=NULL) free(dev->sreg[i].reg); + free(dev->sreg); + free(dev); + return NULL; + } + + dev->num_sregs = num_sregs; + dev->current_dr = 0; + dev->tck_rise = NULL; + dev->tck_fall = NULL; + dev->dev_free = NULL; + dev->tap_state = RESET; + dev->tdo = dev->tdo_buffer = 1; + + return dev; +} + +jim_state_t *jim_init(void) +{ + jim_state_t *s; + + s = (jim_state_t *)malloc(sizeof(jim_state_t)); + if(s == NULL) + { + printf("Out of memory!\n"); + return NULL; + }; + + s->trst = 0; + s->last_device_in_chain = some_cpu(); + if(s->last_device_in_chain != NULL) + { + s->last_device_in_chain->prev = NULL; + } + else + { + printf("Out of memory!\n"); + return NULL; + } + return s; +} + +void jim_free(jim_state_t *s) +{ + jim_device_t *dev, *pre; + + if(s == NULL) return; + + for(dev = s->last_device_in_chain; dev; dev=pre) + { + int i; + + if(dev->dev_free != NULL) dev->dev_free(dev); + for(i=0;inum_sregs;i++) + { + free(dev->sreg[i].reg); + } + free(dev->sreg); + pre = dev->prev; + free(dev); + } + + s->last_device_in_chain = NULL; + + free(s); +} + + diff --git a/jtag/src/tap/cable/jim.c b/jtag/src/tap/cable/jim.c index a49a7ff0..a65e92d3 100644 --- a/jtag/src/tap/cable/jim.c +++ b/jtag/src/tap/cable/jim.c @@ -35,6 +35,15 @@ #include +#include + +/* private parameters of this cable driver */ +typedef struct +{ + jim_state_t *s; +} +jim_cable_params_t; + int jim_cable_connect( char *params[], cable_t *cable ) { @@ -43,7 +52,31 @@ jim_cable_connect( char *params[], cable_t *cable ) return 1; } + printf( _("JTAG target simulator JIM - work in progress!\n")); + cable->chain = NULL; + cable->params = (jim_cable_params_t *)malloc(sizeof(jim_cable_params_t)); + + if(cable->params != NULL) + { + jim_state_t *s; + s = jim_init(); + if(s == NULL) + { + free(cable->params); + cable->params = NULL; + } + else + { + ((jim_cable_params_t *)(cable->params))->s = s; + } + } + + if(cable->params == NULL) + { + printf(_("Initialization failed.\n")); + return 1; + }; return 0; } @@ -58,6 +91,11 @@ jim_cable_disconnect( cable_t *cable ) void jim_cable_free( cable_t *cable ) { + if(cable->params != NULL) + { + jim_free( ((jim_cable_params_t*)(cable->params))->s ); + free( cable->params ); + }; free( cable ); } @@ -69,31 +107,45 @@ jim_cable_done( cable_t *cable ) static int jim_cable_init( cable_t *cable ) { - printf( _("JTAG target simulator JIM - work in progress!\n")); return 0; } static void jim_cable_clock( cable_t *cable, int tms, int tdi, int n ) { + int i; + jim_cable_params_t *jcp = (jim_cable_params_t*)(cable->params); + + for(i = 0; i < n; i++) + { + jim_tck_rise( jcp->s, tms, tdi ); + jim_tck_fall( jcp->s ); + } } static int jim_cable_get_tdo( cable_t *cable ) { - return 0; + jim_cable_params_t *jcp = (jim_cable_params_t*)(cable->params); + + return jim_get_tdo( jcp->s ); } static int jim_cable_get_trst( cable_t *cable ) { - return 0; + jim_cable_params_t *jcp = (jim_cable_params_t*)(cable->params); + + return jim_get_trst( jcp->s ); } static int jim_cable_set_trst( cable_t *cable, int trst ) { - return jim_cable_get_trst( cable ); + jim_cable_params_t *jcp = (jim_cable_params_t*)(cable->params); + + jim_set_trst( jcp->s, trst ); + return jim_get_trst( jcp->s ); } static void