| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * altera.c | 
|  | 3 | * | 
|  | 4 | * altera FPGA driver | 
|  | 5 | * | 
|  | 6 | * Copyright (C) Altera Corporation 1998-2001 | 
|  | 7 | * Copyright (C) 2010,2011 NetUP Inc. | 
|  | 8 | * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru> | 
|  | 9 | * | 
|  | 10 | * This program is free software; you can redistribute it and/or modify | 
|  | 11 | * it under the terms of the GNU General Public License as published by | 
|  | 12 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 13 | * (at your option) any later version. | 
|  | 14 | * | 
|  | 15 | * This program is distributed in the hope that it will be useful, | 
|  | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 18 | * | 
|  | 19 | * GNU General Public License for more details. | 
|  | 20 | * | 
|  | 21 | * You should have received a copy of the GNU General Public License | 
|  | 22 | * along with this program; if not, write to the Free Software | 
|  | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
|  | 24 | */ | 
|  | 25 |  | 
|  | 26 | #include <asm/unaligned.h> | 
|  | 27 | #include <linux/ctype.h> | 
|  | 28 | #include <linux/string.h> | 
|  | 29 | #include <linux/firmware.h> | 
|  | 30 | #include <linux/slab.h> | 
| Paul Gortmaker | 99c9785 | 2011-07-03 15:49:50 -0400 | [diff] [blame] | 31 | #include <linux/module.h> | 
| Igor M. Liplianin | cff4fa8 | 2011-09-23 11:17:41 -0300 | [diff] [blame] | 32 | #include <misc/altera.h> | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 33 | #include "altera-exprt.h" | 
|  | 34 | #include "altera-jtag.h" | 
|  | 35 |  | 
|  | 36 | static int debug = 1; | 
|  | 37 | module_param(debug, int, 0644); | 
|  | 38 | MODULE_PARM_DESC(debug, "enable debugging information"); | 
|  | 39 |  | 
|  | 40 | MODULE_DESCRIPTION("altera FPGA kernel module"); | 
|  | 41 | MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>"); | 
|  | 42 | MODULE_LICENSE("GPL"); | 
|  | 43 |  | 
|  | 44 | #define dprintk(args...) \ | 
|  | 45 | if (debug) { \ | 
|  | 46 | printk(KERN_DEBUG args); \ | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | enum altera_fpga_opcode { | 
|  | 50 | OP_NOP = 0, | 
|  | 51 | OP_DUP, | 
|  | 52 | OP_SWP, | 
|  | 53 | OP_ADD, | 
|  | 54 | OP_SUB, | 
|  | 55 | OP_MULT, | 
|  | 56 | OP_DIV, | 
|  | 57 | OP_MOD, | 
|  | 58 | OP_SHL, | 
|  | 59 | OP_SHR, | 
|  | 60 | OP_NOT, | 
|  | 61 | OP_AND, | 
|  | 62 | OP_OR, | 
|  | 63 | OP_XOR, | 
|  | 64 | OP_INV, | 
|  | 65 | OP_GT, | 
|  | 66 | OP_LT, | 
|  | 67 | OP_RET, | 
|  | 68 | OP_CMPS, | 
|  | 69 | OP_PINT, | 
|  | 70 | OP_PRNT, | 
|  | 71 | OP_DSS, | 
|  | 72 | OP_DSSC, | 
|  | 73 | OP_ISS, | 
|  | 74 | OP_ISSC, | 
|  | 75 | OP_DPR = 0x1c, | 
|  | 76 | OP_DPRL, | 
|  | 77 | OP_DPO, | 
|  | 78 | OP_DPOL, | 
|  | 79 | OP_IPR, | 
|  | 80 | OP_IPRL, | 
|  | 81 | OP_IPO, | 
|  | 82 | OP_IPOL, | 
|  | 83 | OP_PCHR, | 
|  | 84 | OP_EXIT, | 
|  | 85 | OP_EQU, | 
|  | 86 | OP_POPT, | 
|  | 87 | OP_ABS = 0x2c, | 
|  | 88 | OP_BCH0, | 
|  | 89 | OP_PSH0 = 0x2f, | 
|  | 90 | OP_PSHL = 0x40, | 
|  | 91 | OP_PSHV, | 
|  | 92 | OP_JMP, | 
|  | 93 | OP_CALL, | 
|  | 94 | OP_NEXT, | 
|  | 95 | OP_PSTR, | 
|  | 96 | OP_SINT = 0x47, | 
|  | 97 | OP_ST, | 
|  | 98 | OP_ISTP, | 
|  | 99 | OP_DSTP, | 
|  | 100 | OP_SWPN, | 
|  | 101 | OP_DUPN, | 
|  | 102 | OP_POPV, | 
|  | 103 | OP_POPE, | 
|  | 104 | OP_POPA, | 
|  | 105 | OP_JMPZ, | 
|  | 106 | OP_DS, | 
|  | 107 | OP_IS, | 
|  | 108 | OP_DPRA, | 
|  | 109 | OP_DPOA, | 
|  | 110 | OP_IPRA, | 
|  | 111 | OP_IPOA, | 
|  | 112 | OP_EXPT, | 
|  | 113 | OP_PSHE, | 
|  | 114 | OP_PSHA, | 
|  | 115 | OP_DYNA, | 
|  | 116 | OP_EXPV = 0x5c, | 
|  | 117 | OP_COPY = 0x80, | 
|  | 118 | OP_REVA, | 
|  | 119 | OP_DSC, | 
|  | 120 | OP_ISC, | 
|  | 121 | OP_WAIT, | 
|  | 122 | OP_VS, | 
|  | 123 | OP_CMPA = 0xc0, | 
|  | 124 | OP_VSC, | 
|  | 125 | }; | 
|  | 126 |  | 
|  | 127 | struct altera_procinfo { | 
|  | 128 | char			*name; | 
|  | 129 | u8			attrs; | 
|  | 130 | struct altera_procinfo	*next; | 
|  | 131 | }; | 
|  | 132 |  | 
|  | 133 | /* This function checks if enough parameters are available on the stack. */ | 
|  | 134 | static int altera_check_stack(int stack_ptr, int count, int *status) | 
|  | 135 | { | 
|  | 136 | if (stack_ptr < count) { | 
|  | 137 | *status = -EOVERFLOW; | 
|  | 138 | return 0; | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | return 1; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | static void altera_export_int(char *key, s32 value) | 
|  | 145 | { | 
|  | 146 | dprintk("Export: key = \"%s\", value = %d\n", key, value); | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | #define HEX_LINE_CHARS 72 | 
|  | 150 | #define HEX_LINE_BITS (HEX_LINE_CHARS * 4) | 
|  | 151 |  | 
|  | 152 | static void altera_export_bool_array(char *key, u8 *data, s32 count) | 
|  | 153 | { | 
|  | 154 | char string[HEX_LINE_CHARS + 1]; | 
|  | 155 | s32 i, offset; | 
|  | 156 | u32 size, line, lines, linebits, value, j, k; | 
|  | 157 |  | 
|  | 158 | if (count > HEX_LINE_BITS) { | 
|  | 159 | dprintk("Export: key = \"%s\", %d bits, value = HEX\n", | 
|  | 160 | key, count); | 
|  | 161 | lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS; | 
|  | 162 |  | 
|  | 163 | for (line = 0; line < lines; ++line) { | 
|  | 164 | if (line < (lines - 1)) { | 
|  | 165 | linebits = HEX_LINE_BITS; | 
|  | 166 | size = HEX_LINE_CHARS; | 
|  | 167 | offset = count - ((line + 1) * HEX_LINE_BITS); | 
|  | 168 | } else { | 
|  | 169 | linebits = | 
|  | 170 | count - ((lines - 1) * HEX_LINE_BITS); | 
|  | 171 | size = (linebits + 3) / 4; | 
|  | 172 | offset = 0L; | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | string[size] = '\0'; | 
|  | 176 | j = size - 1; | 
|  | 177 | value = 0; | 
|  | 178 |  | 
|  | 179 | for (k = 0; k < linebits; ++k) { | 
|  | 180 | i = k + offset; | 
|  | 181 | if (data[i >> 3] & (1 << (i & 7))) | 
|  | 182 | value |= (1 << (i & 3)); | 
|  | 183 | if ((i & 3) == 3) { | 
|  | 184 | sprintf(&string[j], "%1x", value); | 
|  | 185 | value = 0; | 
|  | 186 | --j; | 
|  | 187 | } | 
|  | 188 | } | 
|  | 189 | if ((k & 3) > 0) | 
|  | 190 | sprintf(&string[j], "%1x", value); | 
|  | 191 |  | 
|  | 192 | dprintk("%s\n", string); | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | } else { | 
|  | 196 | size = (count + 3) / 4; | 
|  | 197 | string[size] = '\0'; | 
|  | 198 | j = size - 1; | 
|  | 199 | value = 0; | 
|  | 200 |  | 
|  | 201 | for (i = 0; i < count; ++i) { | 
|  | 202 | if (data[i >> 3] & (1 << (i & 7))) | 
|  | 203 | value |= (1 << (i & 3)); | 
|  | 204 | if ((i & 3) == 3) { | 
|  | 205 | sprintf(&string[j], "%1x", value); | 
|  | 206 | value = 0; | 
|  | 207 | --j; | 
|  | 208 | } | 
|  | 209 | } | 
|  | 210 | if ((i & 3) > 0) | 
|  | 211 | sprintf(&string[j], "%1x", value); | 
|  | 212 |  | 
|  | 213 | dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n", | 
|  | 214 | key, count, string); | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | static int altera_execute(struct altera_state *astate, | 
|  | 219 | u8 *p, | 
|  | 220 | s32 program_size, | 
|  | 221 | s32 *error_address, | 
|  | 222 | int *exit_code, | 
|  | 223 | int *format_version) | 
|  | 224 | { | 
|  | 225 | struct altera_config *aconf = astate->config; | 
|  | 226 | char *msg_buff = astate->msg_buff; | 
|  | 227 | long *stack = astate->stack; | 
|  | 228 | int status = 0; | 
|  | 229 | u32 first_word = 0L; | 
|  | 230 | u32 action_table = 0L; | 
|  | 231 | u32 proc_table = 0L; | 
|  | 232 | u32 str_table = 0L; | 
|  | 233 | u32 sym_table = 0L; | 
|  | 234 | u32 data_sect = 0L; | 
|  | 235 | u32 code_sect = 0L; | 
|  | 236 | u32 debug_sect = 0L; | 
|  | 237 | u32 action_count = 0L; | 
|  | 238 | u32 proc_count = 0L; | 
|  | 239 | u32 sym_count = 0L; | 
|  | 240 | long *vars = NULL; | 
|  | 241 | s32 *var_size = NULL; | 
|  | 242 | char *attrs = NULL; | 
|  | 243 | u8 *proc_attributes = NULL; | 
|  | 244 | u32 pc; | 
|  | 245 | u32 opcode_address; | 
|  | 246 | u32 args[3]; | 
|  | 247 | u32 opcode; | 
|  | 248 | u32 name_id; | 
|  | 249 | u8 charbuf[4]; | 
|  | 250 | long long_tmp; | 
|  | 251 | u32 variable_id; | 
|  | 252 | u8 *charptr_tmp; | 
|  | 253 | u8 *charptr_tmp2; | 
|  | 254 | long *longptr_tmp; | 
|  | 255 | int version = 0; | 
|  | 256 | int delta = 0; | 
|  | 257 | int stack_ptr = 0; | 
|  | 258 | u32 arg_count; | 
|  | 259 | int done = 0; | 
|  | 260 | int bad_opcode = 0; | 
|  | 261 | u32 count; | 
|  | 262 | u32 index; | 
|  | 263 | u32 index2; | 
|  | 264 | s32 long_count; | 
|  | 265 | s32 long_idx; | 
|  | 266 | s32 long_idx2; | 
|  | 267 | u32 i; | 
|  | 268 | u32 j; | 
|  | 269 | u32 uncomp_size; | 
|  | 270 | u32 offset; | 
|  | 271 | u32 value; | 
|  | 272 | int current_proc = 0; | 
|  | 273 | int reverse; | 
|  | 274 |  | 
|  | 275 | char *name; | 
|  | 276 |  | 
|  | 277 | dprintk("%s\n", __func__); | 
|  | 278 |  | 
|  | 279 | /* Read header information */ | 
|  | 280 | if (program_size > 52L) { | 
|  | 281 | first_word    = get_unaligned_be32(&p[0]); | 
|  | 282 | version = (first_word & 1L); | 
|  | 283 | *format_version = version + 1; | 
|  | 284 | delta = version * 8; | 
|  | 285 |  | 
|  | 286 | action_table  = get_unaligned_be32(&p[4]); | 
|  | 287 | proc_table    = get_unaligned_be32(&p[8]); | 
|  | 288 | str_table  = get_unaligned_be32(&p[4 + delta]); | 
|  | 289 | sym_table  = get_unaligned_be32(&p[16 + delta]); | 
|  | 290 | data_sect  = get_unaligned_be32(&p[20 + delta]); | 
|  | 291 | code_sect  = get_unaligned_be32(&p[24 + delta]); | 
|  | 292 | debug_sect = get_unaligned_be32(&p[28 + delta]); | 
|  | 293 | action_count  = get_unaligned_be32(&p[40 + delta]); | 
|  | 294 | proc_count    = get_unaligned_be32(&p[44 + delta]); | 
|  | 295 | sym_count  = get_unaligned_be32(&p[48 + (2 * delta)]); | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) { | 
|  | 299 | done = 1; | 
|  | 300 | status = -EIO; | 
|  | 301 | goto exit_done; | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | if (sym_count <= 0) | 
|  | 305 | goto exit_done; | 
|  | 306 |  | 
|  | 307 | vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); | 
|  | 308 |  | 
|  | 309 | if (vars == NULL) | 
|  | 310 | status = -ENOMEM; | 
|  | 311 |  | 
|  | 312 | if (status == 0) { | 
|  | 313 | var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); | 
|  | 314 |  | 
|  | 315 | if (var_size == NULL) | 
|  | 316 | status = -ENOMEM; | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | if (status == 0) { | 
|  | 320 | attrs = kzalloc(sym_count, GFP_KERNEL); | 
|  | 321 |  | 
|  | 322 | if (attrs == NULL) | 
|  | 323 | status = -ENOMEM; | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | if ((status == 0) && (version > 0)) { | 
|  | 327 | proc_attributes = kzalloc(proc_count, GFP_KERNEL); | 
|  | 328 |  | 
|  | 329 | if (proc_attributes == NULL) | 
|  | 330 | status = -ENOMEM; | 
|  | 331 | } | 
|  | 332 |  | 
|  | 333 | if (status != 0) | 
|  | 334 | goto exit_done; | 
|  | 335 |  | 
|  | 336 | delta = version * 2; | 
|  | 337 |  | 
|  | 338 | for (i = 0; i < sym_count; ++i) { | 
|  | 339 | offset = (sym_table + ((11 + delta) * i)); | 
|  | 340 |  | 
|  | 341 | value = get_unaligned_be32(&p[offset + 3 + delta]); | 
|  | 342 |  | 
|  | 343 | attrs[i] = p[offset]; | 
|  | 344 |  | 
|  | 345 | /* | 
|  | 346 | * use bit 7 of attribute byte to indicate that | 
|  | 347 | * this buffer was dynamically allocated | 
|  | 348 | * and should be freed later | 
|  | 349 | */ | 
|  | 350 | attrs[i] &= 0x7f; | 
|  | 351 |  | 
|  | 352 | var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]); | 
|  | 353 |  | 
|  | 354 | /* | 
|  | 355 | * Attribute bits: | 
|  | 356 | * bit 0: 0 = read-only, 1 = read-write | 
|  | 357 | * bit 1: 0 = not compressed, 1 = compressed | 
|  | 358 | * bit 2: 0 = not initialized, 1 = initialized | 
|  | 359 | * bit 3: 0 = scalar, 1 = array | 
|  | 360 | * bit 4: 0 = Boolean, 1 = integer | 
|  | 361 | * bit 5: 0 = declared variable, | 
|  | 362 | *	1 = compiler created temporary variable | 
|  | 363 | */ | 
|  | 364 |  | 
|  | 365 | if ((attrs[i] & 0x0c) == 0x04) | 
|  | 366 | /* initialized scalar variable */ | 
|  | 367 | vars[i] = value; | 
|  | 368 | else if ((attrs[i] & 0x1e) == 0x0e) { | 
|  | 369 | /* initialized compressed Boolean array */ | 
|  | 370 | uncomp_size = get_unaligned_le32(&p[data_sect + value]); | 
|  | 371 |  | 
|  | 372 | /* allocate a buffer for the uncompressed data */ | 
|  | 373 | vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL); | 
|  | 374 | if (vars[i] == 0L) | 
|  | 375 | status = -ENOMEM; | 
|  | 376 | else { | 
|  | 377 | /* set flag so buffer will be freed later */ | 
|  | 378 | attrs[i] |= 0x80; | 
|  | 379 |  | 
|  | 380 | /* uncompress the data */ | 
|  | 381 | if (altera_shrink(&p[data_sect + value], | 
|  | 382 | var_size[i], | 
|  | 383 | (u8 *)vars[i], | 
|  | 384 | uncomp_size, | 
|  | 385 | version) != uncomp_size) | 
|  | 386 | /* decompression failed */ | 
|  | 387 | status = -EIO; | 
|  | 388 | else | 
|  | 389 | var_size[i] = uncomp_size * 8L; | 
|  | 390 |  | 
|  | 391 | } | 
|  | 392 | } else if ((attrs[i] & 0x1e) == 0x0c) { | 
|  | 393 | /* initialized Boolean array */ | 
|  | 394 | vars[i] = value + data_sect + (long)p; | 
|  | 395 | } else if ((attrs[i] & 0x1c) == 0x1c) { | 
|  | 396 | /* initialized integer array */ | 
|  | 397 | vars[i] = value + data_sect; | 
|  | 398 | } else if ((attrs[i] & 0x0c) == 0x08) { | 
|  | 399 | /* uninitialized array */ | 
|  | 400 |  | 
|  | 401 | /* flag attrs so that memory is freed */ | 
|  | 402 | attrs[i] |= 0x80; | 
|  | 403 |  | 
|  | 404 | if (var_size[i] > 0) { | 
|  | 405 | u32 size; | 
|  | 406 |  | 
|  | 407 | if (attrs[i] & 0x10) | 
|  | 408 | /* integer array */ | 
|  | 409 | size = (var_size[i] * sizeof(s32)); | 
|  | 410 | else | 
|  | 411 | /* Boolean array */ | 
|  | 412 | size = ((var_size[i] + 7L) / 8L); | 
|  | 413 |  | 
|  | 414 | vars[i] = (long)kzalloc(size, GFP_KERNEL); | 
|  | 415 |  | 
|  | 416 | if (vars[i] == 0) { | 
|  | 417 | status = -ENOMEM; | 
|  | 418 | } else { | 
|  | 419 | /* zero out memory */ | 
|  | 420 | for (j = 0; j < size; ++j) | 
|  | 421 | ((u8 *)(vars[i]))[j] = 0; | 
|  | 422 |  | 
|  | 423 | } | 
|  | 424 | } else | 
|  | 425 | vars[i] = 0; | 
|  | 426 |  | 
|  | 427 | } else | 
|  | 428 | vars[i] = 0; | 
|  | 429 |  | 
|  | 430 | } | 
|  | 431 |  | 
|  | 432 | exit_done: | 
|  | 433 | if (status != 0) | 
|  | 434 | done = 1; | 
|  | 435 |  | 
|  | 436 | altera_jinit(astate); | 
|  | 437 |  | 
|  | 438 | pc = code_sect; | 
|  | 439 | msg_buff[0] = '\0'; | 
|  | 440 |  | 
|  | 441 | /* | 
|  | 442 | * For JBC version 2, we will execute the procedures corresponding to | 
|  | 443 | * the selected ACTION | 
|  | 444 | */ | 
|  | 445 | if (version > 0) { | 
|  | 446 | if (aconf->action == NULL) { | 
|  | 447 | status = -EINVAL; | 
|  | 448 | done = 1; | 
|  | 449 | } else { | 
|  | 450 | int action_found = 0; | 
|  | 451 | for (i = 0; (i < action_count) && !action_found; ++i) { | 
|  | 452 | name_id = get_unaligned_be32(&p[action_table + | 
|  | 453 | (12 * i)]); | 
|  | 454 |  | 
|  | 455 | name = &p[str_table + name_id]; | 
|  | 456 |  | 
|  | 457 | if (strnicmp(aconf->action, name, strlen(name)) == 0) { | 
|  | 458 | action_found = 1; | 
|  | 459 | current_proc = | 
|  | 460 | get_unaligned_be32(&p[action_table + | 
|  | 461 | (12 * i) + 8]); | 
|  | 462 | } | 
|  | 463 | } | 
|  | 464 |  | 
|  | 465 | if (!action_found) { | 
|  | 466 | status = -EINVAL; | 
|  | 467 | done = 1; | 
|  | 468 | } | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | if (status == 0) { | 
|  | 472 | int first_time = 1; | 
|  | 473 | i = current_proc; | 
|  | 474 | while ((i != 0) || first_time) { | 
|  | 475 | first_time = 0; | 
|  | 476 | /* check procedure attribute byte */ | 
|  | 477 | proc_attributes[i] = | 
|  | 478 | (p[proc_table + | 
|  | 479 | (13 * i) + 8] & | 
|  | 480 | 0x03); | 
|  | 481 |  | 
|  | 482 | /* | 
|  | 483 | * BIT0 - OPTIONAL | 
|  | 484 | * BIT1 - RECOMMENDED | 
|  | 485 | * BIT6 - FORCED OFF | 
|  | 486 | * BIT7 - FORCED ON | 
|  | 487 | */ | 
|  | 488 |  | 
|  | 489 | i = get_unaligned_be32(&p[proc_table + | 
|  | 490 | (13 * i) + 4]); | 
|  | 491 | } | 
|  | 492 |  | 
|  | 493 | /* | 
|  | 494 | * Set current_proc to the first procedure | 
|  | 495 | * to be executed | 
|  | 496 | */ | 
|  | 497 | i = current_proc; | 
|  | 498 | while ((i != 0) && | 
|  | 499 | ((proc_attributes[i] == 1) || | 
|  | 500 | ((proc_attributes[i] & 0xc0) == 0x40))) { | 
|  | 501 | i = get_unaligned_be32(&p[proc_table + | 
|  | 502 | (13 * i) + 4]); | 
|  | 503 | } | 
|  | 504 |  | 
|  | 505 | if ((i != 0) || ((i == 0) && (current_proc == 0) && | 
|  | 506 | ((proc_attributes[0] != 1) && | 
|  | 507 | ((proc_attributes[0] & 0xc0) != 0x40)))) { | 
|  | 508 | current_proc = i; | 
|  | 509 | pc = code_sect + | 
|  | 510 | get_unaligned_be32(&p[proc_table + | 
|  | 511 | (13 * i) + 9]); | 
|  | 512 | if ((pc < code_sect) || (pc >= debug_sect)) | 
|  | 513 | status = -ERANGE; | 
|  | 514 | } else | 
|  | 515 | /* there are no procedures to execute! */ | 
|  | 516 | done = 1; | 
|  | 517 |  | 
|  | 518 | } | 
|  | 519 | } | 
|  | 520 |  | 
|  | 521 | msg_buff[0] = '\0'; | 
|  | 522 |  | 
|  | 523 | while (!done) { | 
|  | 524 | opcode = (p[pc] & 0xff); | 
|  | 525 | opcode_address = pc; | 
|  | 526 | ++pc; | 
|  | 527 |  | 
|  | 528 | if (debug > 1) | 
|  | 529 | printk("opcode: %02x\n", opcode); | 
|  | 530 |  | 
|  | 531 | arg_count = (opcode >> 6) & 3; | 
|  | 532 | for (i = 0; i < arg_count; ++i) { | 
|  | 533 | args[i] = get_unaligned_be32(&p[pc]); | 
|  | 534 | pc += 4; | 
|  | 535 | } | 
|  | 536 |  | 
|  | 537 | switch (opcode) { | 
|  | 538 | case OP_NOP: | 
|  | 539 | break; | 
|  | 540 | case OP_DUP: | 
|  | 541 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 542 | stack[stack_ptr] = stack[stack_ptr - 1]; | 
|  | 543 | ++stack_ptr; | 
|  | 544 | } | 
|  | 545 | break; | 
|  | 546 | case OP_SWP: | 
|  | 547 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 548 | long_tmp = stack[stack_ptr - 2]; | 
|  | 549 | stack[stack_ptr - 2] = stack[stack_ptr - 1]; | 
|  | 550 | stack[stack_ptr - 1] = long_tmp; | 
|  | 551 | } | 
|  | 552 | break; | 
|  | 553 | case OP_ADD: | 
|  | 554 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 555 | --stack_ptr; | 
|  | 556 | stack[stack_ptr - 1] += stack[stack_ptr]; | 
|  | 557 | } | 
|  | 558 | break; | 
|  | 559 | case OP_SUB: | 
|  | 560 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 561 | --stack_ptr; | 
|  | 562 | stack[stack_ptr - 1] -= stack[stack_ptr]; | 
|  | 563 | } | 
|  | 564 | break; | 
|  | 565 | case OP_MULT: | 
|  | 566 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 567 | --stack_ptr; | 
|  | 568 | stack[stack_ptr - 1] *= stack[stack_ptr]; | 
|  | 569 | } | 
|  | 570 | break; | 
|  | 571 | case OP_DIV: | 
|  | 572 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 573 | --stack_ptr; | 
|  | 574 | stack[stack_ptr - 1] /= stack[stack_ptr]; | 
|  | 575 | } | 
|  | 576 | break; | 
|  | 577 | case OP_MOD: | 
|  | 578 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 579 | --stack_ptr; | 
|  | 580 | stack[stack_ptr - 1] %= stack[stack_ptr]; | 
|  | 581 | } | 
|  | 582 | break; | 
|  | 583 | case OP_SHL: | 
|  | 584 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 585 | --stack_ptr; | 
|  | 586 | stack[stack_ptr - 1] <<= stack[stack_ptr]; | 
|  | 587 | } | 
|  | 588 | break; | 
|  | 589 | case OP_SHR: | 
|  | 590 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 591 | --stack_ptr; | 
|  | 592 | stack[stack_ptr - 1] >>= stack[stack_ptr]; | 
|  | 593 | } | 
|  | 594 | break; | 
|  | 595 | case OP_NOT: | 
|  | 596 | if (altera_check_stack(stack_ptr, 1, &status)) | 
|  | 597 | stack[stack_ptr - 1] ^= (-1L); | 
|  | 598 |  | 
|  | 599 | break; | 
|  | 600 | case OP_AND: | 
|  | 601 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 602 | --stack_ptr; | 
|  | 603 | stack[stack_ptr - 1] &= stack[stack_ptr]; | 
|  | 604 | } | 
|  | 605 | break; | 
|  | 606 | case OP_OR: | 
|  | 607 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 608 | --stack_ptr; | 
|  | 609 | stack[stack_ptr - 1] |= stack[stack_ptr]; | 
|  | 610 | } | 
|  | 611 | break; | 
|  | 612 | case OP_XOR: | 
|  | 613 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 614 | --stack_ptr; | 
|  | 615 | stack[stack_ptr - 1] ^= stack[stack_ptr]; | 
|  | 616 | } | 
|  | 617 | break; | 
|  | 618 | case OP_INV: | 
|  | 619 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 620 | break; | 
|  | 621 | stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L; | 
|  | 622 | break; | 
|  | 623 | case OP_GT: | 
|  | 624 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 625 | break; | 
|  | 626 | --stack_ptr; | 
|  | 627 | stack[stack_ptr - 1] = | 
|  | 628 | (stack[stack_ptr - 1] > stack[stack_ptr]) ? | 
|  | 629 | 1L : 0L; | 
|  | 630 |  | 
|  | 631 | break; | 
|  | 632 | case OP_LT: | 
|  | 633 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 634 | break; | 
|  | 635 | --stack_ptr; | 
|  | 636 | stack[stack_ptr - 1] = | 
|  | 637 | (stack[stack_ptr - 1] < stack[stack_ptr]) ? | 
|  | 638 | 1L : 0L; | 
|  | 639 |  | 
|  | 640 | break; | 
|  | 641 | case OP_RET: | 
|  | 642 | if ((version > 0) && (stack_ptr == 0)) { | 
|  | 643 | /* | 
|  | 644 | * We completed one of the main procedures | 
|  | 645 | * of an ACTION. | 
|  | 646 | * Find the next procedure | 
|  | 647 | * to be executed and jump to it. | 
|  | 648 | * If there are no more procedures, then EXIT. | 
|  | 649 | */ | 
|  | 650 | i = get_unaligned_be32(&p[proc_table + | 
|  | 651 | (13 * current_proc) + 4]); | 
|  | 652 | while ((i != 0) && | 
|  | 653 | ((proc_attributes[i] == 1) || | 
|  | 654 | ((proc_attributes[i] & 0xc0) == 0x40))) | 
|  | 655 | i = get_unaligned_be32(&p[proc_table + | 
|  | 656 | (13 * i) + 4]); | 
|  | 657 |  | 
|  | 658 | if (i == 0) { | 
|  | 659 | /* no procedures to execute! */ | 
|  | 660 | done = 1; | 
|  | 661 | *exit_code = 0;	/* success */ | 
|  | 662 | } else { | 
|  | 663 | current_proc = i; | 
|  | 664 | pc = code_sect + get_unaligned_be32( | 
|  | 665 | &p[proc_table + | 
|  | 666 | (13 * i) + 9]); | 
|  | 667 | if ((pc < code_sect) || | 
|  | 668 | (pc >= debug_sect)) | 
|  | 669 | status = -ERANGE; | 
|  | 670 | } | 
|  | 671 |  | 
|  | 672 | } else | 
|  | 673 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 674 | pc = stack[--stack_ptr] + code_sect; | 
|  | 675 | if ((pc <= code_sect) || | 
|  | 676 | (pc >= debug_sect)) | 
|  | 677 | status = -ERANGE; | 
|  | 678 |  | 
|  | 679 | } | 
|  | 680 |  | 
|  | 681 | break; | 
|  | 682 | case OP_CMPS: | 
|  | 683 | /* | 
|  | 684 | * Array short compare | 
|  | 685 | * ...stack 0 is source 1 value | 
|  | 686 | * ...stack 1 is source 2 value | 
|  | 687 | * ...stack 2 is mask value | 
|  | 688 | * ...stack 3 is count | 
|  | 689 | */ | 
|  | 690 | if (altera_check_stack(stack_ptr, 4, &status)) { | 
|  | 691 | s32 a = stack[--stack_ptr]; | 
|  | 692 | s32 b = stack[--stack_ptr]; | 
|  | 693 | long_tmp = stack[--stack_ptr]; | 
|  | 694 | count = stack[stack_ptr - 1]; | 
|  | 695 |  | 
|  | 696 | if ((count < 1) || (count > 32)) | 
|  | 697 | status = -ERANGE; | 
|  | 698 | else { | 
|  | 699 | long_tmp &= ((-1L) >> (32 - count)); | 
|  | 700 |  | 
|  | 701 | stack[stack_ptr - 1] = | 
|  | 702 | ((a & long_tmp) == (b & long_tmp)) | 
|  | 703 | ? 1L : 0L; | 
|  | 704 | } | 
|  | 705 | } | 
|  | 706 | break; | 
|  | 707 | case OP_PINT: | 
|  | 708 | /* | 
|  | 709 | * PRINT add integer | 
|  | 710 | * ...stack 0 is integer value | 
|  | 711 | */ | 
|  | 712 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 713 | break; | 
|  | 714 | sprintf(&msg_buff[strlen(msg_buff)], | 
|  | 715 | "%ld", stack[--stack_ptr]); | 
|  | 716 | break; | 
|  | 717 | case OP_PRNT: | 
|  | 718 | /* PRINT finish */ | 
|  | 719 | if (debug) | 
|  | 720 | printk(msg_buff, "\n"); | 
|  | 721 |  | 
|  | 722 | msg_buff[0] = '\0'; | 
|  | 723 | break; | 
|  | 724 | case OP_DSS: | 
|  | 725 | /* | 
|  | 726 | * DRSCAN short | 
|  | 727 | * ...stack 0 is scan data | 
|  | 728 | * ...stack 1 is count | 
|  | 729 | */ | 
|  | 730 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 731 | break; | 
|  | 732 | long_tmp = stack[--stack_ptr]; | 
|  | 733 | count = stack[--stack_ptr]; | 
|  | 734 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 735 | status = altera_drscan(astate, count, charbuf, 0); | 
|  | 736 | break; | 
|  | 737 | case OP_DSSC: | 
|  | 738 | /* | 
|  | 739 | * DRSCAN short with capture | 
|  | 740 | * ...stack 0 is scan data | 
|  | 741 | * ...stack 1 is count | 
|  | 742 | */ | 
|  | 743 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 744 | break; | 
|  | 745 | long_tmp = stack[--stack_ptr]; | 
|  | 746 | count = stack[stack_ptr - 1]; | 
|  | 747 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 748 | status = altera_swap_dr(astate, count, charbuf, | 
|  | 749 | 0, charbuf, 0); | 
|  | 750 | stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); | 
|  | 751 | break; | 
|  | 752 | case OP_ISS: | 
|  | 753 | /* | 
|  | 754 | * IRSCAN short | 
|  | 755 | * ...stack 0 is scan data | 
|  | 756 | * ...stack 1 is count | 
|  | 757 | */ | 
|  | 758 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 759 | break; | 
|  | 760 | long_tmp = stack[--stack_ptr]; | 
|  | 761 | count = stack[--stack_ptr]; | 
|  | 762 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 763 | status = altera_irscan(astate, count, charbuf, 0); | 
|  | 764 | break; | 
|  | 765 | case OP_ISSC: | 
|  | 766 | /* | 
|  | 767 | * IRSCAN short with capture | 
|  | 768 | * ...stack 0 is scan data | 
|  | 769 | * ...stack 1 is count | 
|  | 770 | */ | 
|  | 771 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 772 | break; | 
|  | 773 | long_tmp = stack[--stack_ptr]; | 
|  | 774 | count = stack[stack_ptr - 1]; | 
|  | 775 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 776 | status = altera_swap_ir(astate, count, charbuf, | 
|  | 777 | 0, charbuf, 0); | 
|  | 778 | stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); | 
|  | 779 | break; | 
|  | 780 | case OP_DPR: | 
|  | 781 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 782 | break; | 
|  | 783 | count = stack[--stack_ptr]; | 
|  | 784 | status = altera_set_dr_pre(&astate->js, count, 0, NULL); | 
|  | 785 | break; | 
|  | 786 | case OP_DPRL: | 
|  | 787 | /* | 
|  | 788 | * DRPRE with literal data | 
|  | 789 | * ...stack 0 is count | 
|  | 790 | * ...stack 1 is literal data | 
|  | 791 | */ | 
|  | 792 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 793 | break; | 
|  | 794 | count = stack[--stack_ptr]; | 
|  | 795 | long_tmp = stack[--stack_ptr]; | 
|  | 796 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 797 | status = altera_set_dr_pre(&astate->js, count, 0, | 
|  | 798 | charbuf); | 
|  | 799 | break; | 
|  | 800 | case OP_DPO: | 
|  | 801 | /* | 
|  | 802 | * DRPOST | 
|  | 803 | * ...stack 0 is count | 
|  | 804 | */ | 
|  | 805 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 806 | count = stack[--stack_ptr]; | 
|  | 807 | status = altera_set_dr_post(&astate->js, count, | 
|  | 808 | 0, NULL); | 
|  | 809 | } | 
|  | 810 | break; | 
|  | 811 | case OP_DPOL: | 
|  | 812 | /* | 
|  | 813 | * DRPOST with literal data | 
|  | 814 | * ...stack 0 is count | 
|  | 815 | * ...stack 1 is literal data | 
|  | 816 | */ | 
|  | 817 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 818 | break; | 
|  | 819 | count = stack[--stack_ptr]; | 
|  | 820 | long_tmp = stack[--stack_ptr]; | 
|  | 821 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 822 | status = altera_set_dr_post(&astate->js, count, 0, | 
|  | 823 | charbuf); | 
|  | 824 | break; | 
|  | 825 | case OP_IPR: | 
|  | 826 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 827 | count = stack[--stack_ptr]; | 
|  | 828 | status = altera_set_ir_pre(&astate->js, count, | 
|  | 829 | 0, NULL); | 
|  | 830 | } | 
|  | 831 | break; | 
|  | 832 | case OP_IPRL: | 
|  | 833 | /* | 
|  | 834 | * IRPRE with literal data | 
|  | 835 | * ...stack 0 is count | 
|  | 836 | * ...stack 1 is literal data | 
|  | 837 | */ | 
|  | 838 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 839 | count = stack[--stack_ptr]; | 
|  | 840 | long_tmp = stack[--stack_ptr]; | 
|  | 841 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 842 | status = altera_set_ir_pre(&astate->js, count, | 
|  | 843 | 0, charbuf); | 
|  | 844 | } | 
|  | 845 | break; | 
|  | 846 | case OP_IPO: | 
|  | 847 | /* | 
|  | 848 | * IRPOST | 
|  | 849 | * ...stack 0 is count | 
|  | 850 | */ | 
|  | 851 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 852 | count = stack[--stack_ptr]; | 
|  | 853 | status = altera_set_ir_post(&astate->js, count, | 
|  | 854 | 0, NULL); | 
|  | 855 | } | 
|  | 856 | break; | 
|  | 857 | case OP_IPOL: | 
|  | 858 | /* | 
|  | 859 | * IRPOST with literal data | 
|  | 860 | * ...stack 0 is count | 
|  | 861 | * ...stack 1 is literal data | 
|  | 862 | */ | 
|  | 863 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 864 | break; | 
|  | 865 | count = stack[--stack_ptr]; | 
|  | 866 | long_tmp = stack[--stack_ptr]; | 
|  | 867 | put_unaligned_le32(long_tmp, &charbuf[0]); | 
|  | 868 | status = altera_set_ir_post(&astate->js, count, 0, | 
|  | 869 | charbuf); | 
|  | 870 | break; | 
|  | 871 | case OP_PCHR: | 
|  | 872 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 873 | u8 ch; | 
|  | 874 | count = strlen(msg_buff); | 
|  | 875 | ch = (char) stack[--stack_ptr]; | 
|  | 876 | if ((ch < 1) || (ch > 127)) { | 
|  | 877 | /* | 
|  | 878 | * character code out of range | 
|  | 879 | * instead of flagging an error, | 
|  | 880 | * force the value to 127 | 
|  | 881 | */ | 
|  | 882 | ch = 127; | 
|  | 883 | } | 
|  | 884 | msg_buff[count] = ch; | 
|  | 885 | msg_buff[count + 1] = '\0'; | 
|  | 886 | } | 
|  | 887 | break; | 
|  | 888 | case OP_EXIT: | 
|  | 889 | if (altera_check_stack(stack_ptr, 1, &status)) | 
|  | 890 | *exit_code = stack[--stack_ptr]; | 
|  | 891 |  | 
|  | 892 | done = 1; | 
|  | 893 | break; | 
|  | 894 | case OP_EQU: | 
|  | 895 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 896 | break; | 
|  | 897 | --stack_ptr; | 
|  | 898 | stack[stack_ptr - 1] = | 
|  | 899 | (stack[stack_ptr - 1] == stack[stack_ptr]) ? | 
|  | 900 | 1L : 0L; | 
|  | 901 | break; | 
|  | 902 | case OP_POPT: | 
|  | 903 | if (altera_check_stack(stack_ptr, 1, &status)) | 
|  | 904 | --stack_ptr; | 
|  | 905 |  | 
|  | 906 | break; | 
|  | 907 | case OP_ABS: | 
|  | 908 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 909 | break; | 
|  | 910 | if (stack[stack_ptr - 1] < 0) | 
|  | 911 | stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1]; | 
|  | 912 |  | 
|  | 913 | break; | 
|  | 914 | case OP_BCH0: | 
|  | 915 | /* | 
|  | 916 | * Batch operation 0 | 
|  | 917 | * SWP | 
|  | 918 | * SWPN 7 | 
|  | 919 | * SWP | 
|  | 920 | * SWPN 6 | 
|  | 921 | * DUPN 8 | 
|  | 922 | * SWPN 2 | 
|  | 923 | * SWP | 
|  | 924 | * DUPN 6 | 
|  | 925 | * DUPN 6 | 
|  | 926 | */ | 
|  | 927 |  | 
|  | 928 | /* SWP  */ | 
|  | 929 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 930 | long_tmp = stack[stack_ptr - 2]; | 
|  | 931 | stack[stack_ptr - 2] = stack[stack_ptr - 1]; | 
|  | 932 | stack[stack_ptr - 1] = long_tmp; | 
|  | 933 | } | 
|  | 934 |  | 
|  | 935 | /* SWPN 7 */ | 
|  | 936 | index = 7 + 1; | 
|  | 937 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 938 | long_tmp = stack[stack_ptr - index]; | 
|  | 939 | stack[stack_ptr - index] = stack[stack_ptr - 1]; | 
|  | 940 | stack[stack_ptr - 1] = long_tmp; | 
|  | 941 | } | 
|  | 942 |  | 
|  | 943 | /* SWP  */ | 
|  | 944 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 945 | long_tmp = stack[stack_ptr - 2]; | 
|  | 946 | stack[stack_ptr - 2] = stack[stack_ptr - 1]; | 
|  | 947 | stack[stack_ptr - 1] = long_tmp; | 
|  | 948 | } | 
|  | 949 |  | 
|  | 950 | /* SWPN 6 */ | 
|  | 951 | index = 6 + 1; | 
|  | 952 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 953 | long_tmp = stack[stack_ptr - index]; | 
|  | 954 | stack[stack_ptr - index] = stack[stack_ptr - 1]; | 
|  | 955 | stack[stack_ptr - 1] = long_tmp; | 
|  | 956 | } | 
|  | 957 |  | 
|  | 958 | /* DUPN 8 */ | 
|  | 959 | index = 8 + 1; | 
|  | 960 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 961 | stack[stack_ptr] = stack[stack_ptr - index]; | 
|  | 962 | ++stack_ptr; | 
|  | 963 | } | 
|  | 964 |  | 
|  | 965 | /* SWPN 2 */ | 
|  | 966 | index = 2 + 1; | 
|  | 967 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 968 | long_tmp = stack[stack_ptr - index]; | 
|  | 969 | stack[stack_ptr - index] = stack[stack_ptr - 1]; | 
|  | 970 | stack[stack_ptr - 1] = long_tmp; | 
|  | 971 | } | 
|  | 972 |  | 
|  | 973 | /* SWP  */ | 
|  | 974 | if (altera_check_stack(stack_ptr, 2, &status)) { | 
|  | 975 | long_tmp = stack[stack_ptr - 2]; | 
|  | 976 | stack[stack_ptr - 2] = stack[stack_ptr - 1]; | 
|  | 977 | stack[stack_ptr - 1] = long_tmp; | 
|  | 978 | } | 
|  | 979 |  | 
|  | 980 | /* DUPN 6 */ | 
|  | 981 | index = 6 + 1; | 
|  | 982 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 983 | stack[stack_ptr] = stack[stack_ptr - index]; | 
|  | 984 | ++stack_ptr; | 
|  | 985 | } | 
|  | 986 |  | 
|  | 987 | /* DUPN 6 */ | 
|  | 988 | index = 6 + 1; | 
|  | 989 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 990 | stack[stack_ptr] = stack[stack_ptr - index]; | 
|  | 991 | ++stack_ptr; | 
|  | 992 | } | 
|  | 993 | break; | 
|  | 994 | case OP_PSH0: | 
|  | 995 | stack[stack_ptr++] = 0; | 
|  | 996 | break; | 
|  | 997 | case OP_PSHL: | 
|  | 998 | stack[stack_ptr++] = (s32) args[0]; | 
|  | 999 | break; | 
|  | 1000 | case OP_PSHV: | 
|  | 1001 | stack[stack_ptr++] = vars[args[0]]; | 
|  | 1002 | break; | 
|  | 1003 | case OP_JMP: | 
|  | 1004 | pc = args[0] + code_sect; | 
|  | 1005 | if ((pc < code_sect) || (pc >= debug_sect)) | 
|  | 1006 | status = -ERANGE; | 
|  | 1007 | break; | 
|  | 1008 | case OP_CALL: | 
|  | 1009 | stack[stack_ptr++] = pc; | 
|  | 1010 | pc = args[0] + code_sect; | 
|  | 1011 | if ((pc < code_sect) || (pc >= debug_sect)) | 
|  | 1012 | status = -ERANGE; | 
|  | 1013 | break; | 
|  | 1014 | case OP_NEXT: | 
|  | 1015 | /* | 
|  | 1016 | * Process FOR / NEXT loop | 
|  | 1017 | * ...argument 0 is variable ID | 
|  | 1018 | * ...stack 0 is step value | 
|  | 1019 | * ...stack 1 is end value | 
|  | 1020 | * ...stack 2 is top address | 
|  | 1021 | */ | 
|  | 1022 | if (altera_check_stack(stack_ptr, 3, &status)) { | 
|  | 1023 | s32 step = stack[stack_ptr - 1]; | 
|  | 1024 | s32 end = stack[stack_ptr - 2]; | 
|  | 1025 | s32 top = stack[stack_ptr - 3]; | 
|  | 1026 | s32 iterator = vars[args[0]]; | 
|  | 1027 | int break_out = 0; | 
|  | 1028 |  | 
|  | 1029 | if (step < 0) { | 
|  | 1030 | if (iterator <= end) | 
|  | 1031 | break_out = 1; | 
|  | 1032 | } else if (iterator >= end) | 
|  | 1033 | break_out = 1; | 
|  | 1034 |  | 
|  | 1035 | if (break_out) { | 
|  | 1036 | stack_ptr -= 3; | 
|  | 1037 | } else { | 
|  | 1038 | vars[args[0]] = iterator + step; | 
|  | 1039 | pc = top + code_sect; | 
|  | 1040 | if ((pc < code_sect) || | 
|  | 1041 | (pc >= debug_sect)) | 
|  | 1042 | status = -ERANGE; | 
|  | 1043 | } | 
|  | 1044 | } | 
|  | 1045 | break; | 
|  | 1046 | case OP_PSTR: | 
|  | 1047 | /* | 
|  | 1048 | * PRINT add string | 
|  | 1049 | * ...argument 0 is string ID | 
|  | 1050 | */ | 
|  | 1051 | count = strlen(msg_buff); | 
|  | 1052 | strlcpy(&msg_buff[count], | 
|  | 1053 | &p[str_table + args[0]], | 
|  | 1054 | ALTERA_MESSAGE_LENGTH - count); | 
|  | 1055 | break; | 
|  | 1056 | case OP_SINT: | 
|  | 1057 | /* | 
|  | 1058 | * STATE intermediate state | 
|  | 1059 | * ...argument 0 is state code | 
|  | 1060 | */ | 
|  | 1061 | status = altera_goto_jstate(astate, args[0]); | 
|  | 1062 | break; | 
|  | 1063 | case OP_ST: | 
|  | 1064 | /* | 
|  | 1065 | * STATE final state | 
|  | 1066 | * ...argument 0 is state code | 
|  | 1067 | */ | 
|  | 1068 | status = altera_goto_jstate(astate, args[0]); | 
|  | 1069 | break; | 
|  | 1070 | case OP_ISTP: | 
|  | 1071 | /* | 
|  | 1072 | * IRSTOP state | 
|  | 1073 | * ...argument 0 is state code | 
|  | 1074 | */ | 
|  | 1075 | status = altera_set_irstop(&astate->js, args[0]); | 
|  | 1076 | break; | 
|  | 1077 | case OP_DSTP: | 
|  | 1078 | /* | 
|  | 1079 | * DRSTOP state | 
|  | 1080 | * ...argument 0 is state code | 
|  | 1081 | */ | 
|  | 1082 | status = altera_set_drstop(&astate->js, args[0]); | 
|  | 1083 | break; | 
|  | 1084 |  | 
|  | 1085 | case OP_SWPN: | 
|  | 1086 | /* | 
|  | 1087 | * Exchange top with Nth stack value | 
|  | 1088 | * ...argument 0 is 0-based stack entry | 
|  | 1089 | * to swap with top element | 
|  | 1090 | */ | 
|  | 1091 | index = (args[0]) + 1; | 
|  | 1092 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 1093 | long_tmp = stack[stack_ptr - index]; | 
|  | 1094 | stack[stack_ptr - index] = stack[stack_ptr - 1]; | 
|  | 1095 | stack[stack_ptr - 1] = long_tmp; | 
|  | 1096 | } | 
|  | 1097 | break; | 
|  | 1098 | case OP_DUPN: | 
|  | 1099 | /* | 
|  | 1100 | * Duplicate Nth stack value | 
|  | 1101 | * ...argument 0 is 0-based stack entry to duplicate | 
|  | 1102 | */ | 
|  | 1103 | index = (args[0]) + 1; | 
|  | 1104 | if (altera_check_stack(stack_ptr, index, &status)) { | 
|  | 1105 | stack[stack_ptr] = stack[stack_ptr - index]; | 
|  | 1106 | ++stack_ptr; | 
|  | 1107 | } | 
|  | 1108 | break; | 
|  | 1109 | case OP_POPV: | 
|  | 1110 | /* | 
|  | 1111 | * Pop stack into scalar variable | 
|  | 1112 | * ...argument 0 is variable ID | 
|  | 1113 | * ...stack 0 is value | 
|  | 1114 | */ | 
|  | 1115 | if (altera_check_stack(stack_ptr, 1, &status)) | 
|  | 1116 | vars[args[0]] = stack[--stack_ptr]; | 
|  | 1117 |  | 
|  | 1118 | break; | 
|  | 1119 | case OP_POPE: | 
|  | 1120 | /* | 
|  | 1121 | * Pop stack into integer array element | 
|  | 1122 | * ...argument 0 is variable ID | 
|  | 1123 | * ...stack 0 is array index | 
|  | 1124 | * ...stack 1 is value | 
|  | 1125 | */ | 
|  | 1126 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1127 | break; | 
|  | 1128 | variable_id = args[0]; | 
|  | 1129 |  | 
|  | 1130 | /* | 
|  | 1131 | * If variable is read-only, | 
|  | 1132 | * convert to writable array | 
|  | 1133 | */ | 
|  | 1134 | if ((version > 0) && | 
|  | 1135 | ((attrs[variable_id] & 0x9c) == 0x1c)) { | 
|  | 1136 | /* Allocate a writable buffer for this array */ | 
|  | 1137 | count = var_size[variable_id]; | 
|  | 1138 | long_tmp = vars[variable_id]; | 
|  | 1139 | longptr_tmp = kzalloc(count * sizeof(long), | 
|  | 1140 | GFP_KERNEL); | 
|  | 1141 | vars[variable_id] = (long)longptr_tmp; | 
|  | 1142 |  | 
|  | 1143 | if (vars[variable_id] == 0) { | 
|  | 1144 | status = -ENOMEM; | 
|  | 1145 | break; | 
|  | 1146 | } | 
|  | 1147 |  | 
|  | 1148 | /* copy previous contents into buffer */ | 
|  | 1149 | for (i = 0; i < count; ++i) { | 
|  | 1150 | longptr_tmp[i] = | 
|  | 1151 | get_unaligned_be32(&p[long_tmp]); | 
|  | 1152 | long_tmp += sizeof(long); | 
|  | 1153 | } | 
|  | 1154 |  | 
|  | 1155 | /* | 
|  | 1156 | * set bit 7 - buffer was | 
|  | 1157 | * dynamically allocated | 
|  | 1158 | */ | 
|  | 1159 | attrs[variable_id] |= 0x80; | 
|  | 1160 |  | 
|  | 1161 | /* clear bit 2 - variable is writable */ | 
|  | 1162 | attrs[variable_id] &= ~0x04; | 
|  | 1163 | attrs[variable_id] |= 0x01; | 
|  | 1164 |  | 
|  | 1165 | } | 
|  | 1166 |  | 
|  | 1167 | /* check that variable is a writable integer array */ | 
|  | 1168 | if ((attrs[variable_id] & 0x1c) != 0x18) | 
|  | 1169 | status = -ERANGE; | 
|  | 1170 | else { | 
|  | 1171 | longptr_tmp = (long *)vars[variable_id]; | 
|  | 1172 |  | 
|  | 1173 | /* pop the array index */ | 
|  | 1174 | index = stack[--stack_ptr]; | 
|  | 1175 |  | 
|  | 1176 | /* pop the value and store it into the array */ | 
|  | 1177 | longptr_tmp[index] = stack[--stack_ptr]; | 
|  | 1178 | } | 
|  | 1179 |  | 
|  | 1180 | break; | 
|  | 1181 | case OP_POPA: | 
|  | 1182 | /* | 
|  | 1183 | * Pop stack into Boolean array | 
|  | 1184 | * ...argument 0 is variable ID | 
|  | 1185 | * ...stack 0 is count | 
|  | 1186 | * ...stack 1 is array index | 
|  | 1187 | * ...stack 2 is value | 
|  | 1188 | */ | 
|  | 1189 | if (!altera_check_stack(stack_ptr, 3, &status)) | 
|  | 1190 | break; | 
|  | 1191 | variable_id = args[0]; | 
|  | 1192 |  | 
|  | 1193 | /* | 
|  | 1194 | * If variable is read-only, | 
|  | 1195 | * convert to writable array | 
|  | 1196 | */ | 
|  | 1197 | if ((version > 0) && | 
|  | 1198 | ((attrs[variable_id] & 0x9c) == 0x0c)) { | 
|  | 1199 | /* Allocate a writable buffer for this array */ | 
|  | 1200 | long_tmp = | 
|  | 1201 | (var_size[variable_id] + 7L) >> 3L; | 
|  | 1202 | charptr_tmp2 = (u8 *)vars[variable_id]; | 
|  | 1203 | charptr_tmp = | 
|  | 1204 | kzalloc(long_tmp, GFP_KERNEL); | 
|  | 1205 | vars[variable_id] = (long)charptr_tmp; | 
|  | 1206 |  | 
|  | 1207 | if (vars[variable_id] == 0) { | 
|  | 1208 | status = -ENOMEM; | 
|  | 1209 | break; | 
|  | 1210 | } | 
|  | 1211 |  | 
|  | 1212 | /* zero the buffer */ | 
|  | 1213 | for (long_idx = 0L; | 
|  | 1214 | long_idx < long_tmp; | 
|  | 1215 | ++long_idx) { | 
|  | 1216 | charptr_tmp[long_idx] = 0; | 
|  | 1217 | } | 
|  | 1218 |  | 
|  | 1219 | /* copy previous contents into buffer */ | 
|  | 1220 | for (long_idx = 0L; | 
|  | 1221 | long_idx < var_size[variable_id]; | 
|  | 1222 | ++long_idx) { | 
|  | 1223 | long_idx2 = long_idx; | 
|  | 1224 |  | 
|  | 1225 | if (charptr_tmp2[long_idx2 >> 3] & | 
|  | 1226 | (1 << (long_idx2 & 7))) { | 
|  | 1227 | charptr_tmp[long_idx >> 3] |= | 
|  | 1228 | (1 << (long_idx & 7)); | 
|  | 1229 | } | 
|  | 1230 | } | 
|  | 1231 |  | 
|  | 1232 | /* | 
|  | 1233 | * set bit 7 - buffer was | 
|  | 1234 | * dynamically allocated | 
|  | 1235 | */ | 
|  | 1236 | attrs[variable_id] |= 0x80; | 
|  | 1237 |  | 
|  | 1238 | /* clear bit 2 - variable is writable */ | 
|  | 1239 | attrs[variable_id] &= ~0x04; | 
|  | 1240 | attrs[variable_id] |= 0x01; | 
|  | 1241 |  | 
|  | 1242 | } | 
|  | 1243 |  | 
|  | 1244 | /* | 
|  | 1245 | * check that variable is | 
|  | 1246 | * a writable Boolean array | 
|  | 1247 | */ | 
|  | 1248 | if ((attrs[variable_id] & 0x1c) != 0x08) { | 
|  | 1249 | status = -ERANGE; | 
|  | 1250 | break; | 
|  | 1251 | } | 
|  | 1252 |  | 
|  | 1253 | charptr_tmp = (u8 *)vars[variable_id]; | 
|  | 1254 |  | 
|  | 1255 | /* pop the count (number of bits to copy) */ | 
|  | 1256 | long_count = stack[--stack_ptr]; | 
|  | 1257 |  | 
|  | 1258 | /* pop the array index */ | 
|  | 1259 | long_idx = stack[--stack_ptr]; | 
|  | 1260 |  | 
|  | 1261 | reverse = 0; | 
|  | 1262 |  | 
|  | 1263 | if (version > 0) { | 
|  | 1264 | /* | 
|  | 1265 | * stack 0 = array right index | 
|  | 1266 | * stack 1 = array left index | 
|  | 1267 | */ | 
|  | 1268 |  | 
|  | 1269 | if (long_idx > long_count) { | 
|  | 1270 | reverse = 1; | 
|  | 1271 | long_tmp = long_count; | 
|  | 1272 | long_count = 1 + long_idx - | 
|  | 1273 | long_count; | 
|  | 1274 | long_idx = long_tmp; | 
|  | 1275 |  | 
|  | 1276 | /* reverse POPA is not supported */ | 
|  | 1277 | status = -ERANGE; | 
|  | 1278 | break; | 
|  | 1279 | } else | 
|  | 1280 | long_count = 1 + long_count - | 
|  | 1281 | long_idx; | 
|  | 1282 |  | 
|  | 1283 | } | 
|  | 1284 |  | 
|  | 1285 | /* pop the data */ | 
|  | 1286 | long_tmp = stack[--stack_ptr]; | 
|  | 1287 |  | 
|  | 1288 | if (long_count < 1) { | 
|  | 1289 | status = -ERANGE; | 
|  | 1290 | break; | 
|  | 1291 | } | 
|  | 1292 |  | 
|  | 1293 | for (i = 0; i < long_count; ++i) { | 
|  | 1294 | if (long_tmp & (1L << (s32) i)) | 
|  | 1295 | charptr_tmp[long_idx >> 3L] |= | 
|  | 1296 | (1L << (long_idx & 7L)); | 
|  | 1297 | else | 
|  | 1298 | charptr_tmp[long_idx >> 3L] &= | 
|  | 1299 | ~(1L << (long_idx & 7L)); | 
|  | 1300 |  | 
|  | 1301 | ++long_idx; | 
|  | 1302 | } | 
|  | 1303 |  | 
|  | 1304 | break; | 
|  | 1305 | case OP_JMPZ: | 
|  | 1306 | /* | 
|  | 1307 | * Pop stack and branch if zero | 
|  | 1308 | * ...argument 0 is address | 
|  | 1309 | * ...stack 0 is condition value | 
|  | 1310 | */ | 
|  | 1311 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 1312 | if (stack[--stack_ptr] == 0) { | 
|  | 1313 | pc = args[0] + code_sect; | 
|  | 1314 | if ((pc < code_sect) || | 
|  | 1315 | (pc >= debug_sect)) | 
|  | 1316 | status = -ERANGE; | 
|  | 1317 | } | 
|  | 1318 | } | 
|  | 1319 | break; | 
|  | 1320 | case OP_DS: | 
|  | 1321 | case OP_IS: | 
|  | 1322 | /* | 
|  | 1323 | * DRSCAN | 
|  | 1324 | * IRSCAN | 
|  | 1325 | * ...argument 0 is scan data variable ID | 
|  | 1326 | * ...stack 0 is array index | 
|  | 1327 | * ...stack 1 is count | 
|  | 1328 | */ | 
|  | 1329 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1330 | break; | 
|  | 1331 | long_idx = stack[--stack_ptr]; | 
|  | 1332 | long_count = stack[--stack_ptr]; | 
|  | 1333 | reverse = 0; | 
|  | 1334 | if (version > 0) { | 
|  | 1335 | /* | 
|  | 1336 | * stack 0 = array right index | 
|  | 1337 | * stack 1 = array left index | 
|  | 1338 | * stack 2 = count | 
|  | 1339 | */ | 
|  | 1340 | long_tmp = long_count; | 
|  | 1341 | long_count = stack[--stack_ptr]; | 
|  | 1342 |  | 
|  | 1343 | if (long_idx > long_tmp) { | 
|  | 1344 | reverse = 1; | 
|  | 1345 | long_idx = long_tmp; | 
|  | 1346 | } | 
|  | 1347 | } | 
|  | 1348 |  | 
|  | 1349 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1350 |  | 
|  | 1351 | if (reverse) { | 
|  | 1352 | /* | 
|  | 1353 | * allocate a buffer | 
|  | 1354 | * and reverse the data order | 
|  | 1355 | */ | 
|  | 1356 | charptr_tmp2 = charptr_tmp; | 
|  | 1357 | charptr_tmp = kzalloc((long_count >> 3) + 1, | 
|  | 1358 | GFP_KERNEL); | 
|  | 1359 | if (charptr_tmp == NULL) { | 
|  | 1360 | status = -ENOMEM; | 
|  | 1361 | break; | 
|  | 1362 | } | 
|  | 1363 |  | 
|  | 1364 | long_tmp = long_idx + long_count - 1; | 
|  | 1365 | long_idx2 = 0; | 
|  | 1366 | while (long_idx2 < long_count) { | 
|  | 1367 | if (charptr_tmp2[long_tmp >> 3] & | 
|  | 1368 | (1 << (long_tmp & 7))) | 
|  | 1369 | charptr_tmp[long_idx2 >> 3] |= | 
|  | 1370 | (1 << (long_idx2 & 7)); | 
|  | 1371 | else | 
|  | 1372 | charptr_tmp[long_idx2 >> 3] &= | 
|  | 1373 | ~(1 << (long_idx2 & 7)); | 
|  | 1374 |  | 
|  | 1375 | --long_tmp; | 
|  | 1376 | ++long_idx2; | 
|  | 1377 | } | 
|  | 1378 | } | 
|  | 1379 |  | 
|  | 1380 | if (opcode == 0x51) /* DS */ | 
|  | 1381 | status = altera_drscan(astate, long_count, | 
|  | 1382 | charptr_tmp, long_idx); | 
|  | 1383 | else /* IS */ | 
|  | 1384 | status = altera_irscan(astate, long_count, | 
|  | 1385 | charptr_tmp, long_idx); | 
|  | 1386 |  | 
|  | 1387 | if (reverse) | 
|  | 1388 | kfree(charptr_tmp); | 
|  | 1389 |  | 
|  | 1390 | break; | 
|  | 1391 | case OP_DPRA: | 
|  | 1392 | /* | 
|  | 1393 | * DRPRE with array data | 
|  | 1394 | * ...argument 0 is variable ID | 
|  | 1395 | * ...stack 0 is array index | 
|  | 1396 | * ...stack 1 is count | 
|  | 1397 | */ | 
|  | 1398 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1399 | break; | 
|  | 1400 | index = stack[--stack_ptr]; | 
|  | 1401 | count = stack[--stack_ptr]; | 
|  | 1402 |  | 
|  | 1403 | if (version > 0) | 
|  | 1404 | /* | 
|  | 1405 | * stack 0 = array right index | 
|  | 1406 | * stack 1 = array left index | 
|  | 1407 | */ | 
|  | 1408 | count = 1 + count - index; | 
|  | 1409 |  | 
|  | 1410 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1411 | status = altera_set_dr_pre(&astate->js, count, index, | 
|  | 1412 | charptr_tmp); | 
|  | 1413 | break; | 
|  | 1414 | case OP_DPOA: | 
|  | 1415 | /* | 
|  | 1416 | * DRPOST with array data | 
|  | 1417 | * ...argument 0 is variable ID | 
|  | 1418 | * ...stack 0 is array index | 
|  | 1419 | * ...stack 1 is count | 
|  | 1420 | */ | 
|  | 1421 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1422 | break; | 
|  | 1423 | index = stack[--stack_ptr]; | 
|  | 1424 | count = stack[--stack_ptr]; | 
|  | 1425 |  | 
|  | 1426 | if (version > 0) | 
|  | 1427 | /* | 
|  | 1428 | * stack 0 = array right index | 
|  | 1429 | * stack 1 = array left index | 
|  | 1430 | */ | 
|  | 1431 | count = 1 + count - index; | 
|  | 1432 |  | 
|  | 1433 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1434 | status = altera_set_dr_post(&astate->js, count, index, | 
|  | 1435 | charptr_tmp); | 
|  | 1436 | break; | 
|  | 1437 | case OP_IPRA: | 
|  | 1438 | /* | 
|  | 1439 | * IRPRE with array data | 
|  | 1440 | * ...argument 0 is variable ID | 
|  | 1441 | * ...stack 0 is array index | 
|  | 1442 | * ...stack 1 is count | 
|  | 1443 | */ | 
|  | 1444 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1445 | break; | 
|  | 1446 | index = stack[--stack_ptr]; | 
|  | 1447 | count = stack[--stack_ptr]; | 
|  | 1448 |  | 
|  | 1449 | if (version > 0) | 
|  | 1450 | /* | 
|  | 1451 | * stack 0 = array right index | 
|  | 1452 | * stack 1 = array left index | 
|  | 1453 | */ | 
|  | 1454 | count = 1 + count - index; | 
|  | 1455 |  | 
|  | 1456 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1457 | status = altera_set_ir_pre(&astate->js, count, index, | 
|  | 1458 | charptr_tmp); | 
|  | 1459 |  | 
|  | 1460 | break; | 
|  | 1461 | case OP_IPOA: | 
|  | 1462 | /* | 
|  | 1463 | * IRPOST with array data | 
|  | 1464 | * ...argument 0 is variable ID | 
|  | 1465 | * ...stack 0 is array index | 
|  | 1466 | * ...stack 1 is count | 
|  | 1467 | */ | 
|  | 1468 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1469 | break; | 
|  | 1470 | index = stack[--stack_ptr]; | 
|  | 1471 | count = stack[--stack_ptr]; | 
|  | 1472 |  | 
|  | 1473 | if (version > 0) | 
|  | 1474 | /* | 
|  | 1475 | * stack 0 = array right index | 
|  | 1476 | * stack 1 = array left index | 
|  | 1477 | */ | 
|  | 1478 | count = 1 + count - index; | 
|  | 1479 |  | 
|  | 1480 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1481 | status = altera_set_ir_post(&astate->js, count, index, | 
|  | 1482 | charptr_tmp); | 
|  | 1483 |  | 
|  | 1484 | break; | 
|  | 1485 | case OP_EXPT: | 
|  | 1486 | /* | 
|  | 1487 | * EXPORT | 
|  | 1488 | * ...argument 0 is string ID | 
|  | 1489 | * ...stack 0 is integer expression | 
|  | 1490 | */ | 
|  | 1491 | if (altera_check_stack(stack_ptr, 1, &status)) { | 
|  | 1492 | name = &p[str_table + args[0]]; | 
|  | 1493 | long_tmp = stack[--stack_ptr]; | 
|  | 1494 | altera_export_int(name, long_tmp); | 
|  | 1495 | } | 
|  | 1496 | break; | 
|  | 1497 | case OP_PSHE: | 
|  | 1498 | /* | 
|  | 1499 | * Push integer array element | 
|  | 1500 | * ...argument 0 is variable ID | 
|  | 1501 | * ...stack 0 is array index | 
|  | 1502 | */ | 
|  | 1503 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 1504 | break; | 
|  | 1505 | variable_id = args[0]; | 
|  | 1506 | index = stack[stack_ptr - 1]; | 
|  | 1507 |  | 
|  | 1508 | /* check variable type */ | 
|  | 1509 | if ((attrs[variable_id] & 0x1f) == 0x19) { | 
|  | 1510 | /* writable integer array */ | 
|  | 1511 | longptr_tmp = (long *)vars[variable_id]; | 
|  | 1512 | stack[stack_ptr - 1] = longptr_tmp[index]; | 
|  | 1513 | } else if ((attrs[variable_id] & 0x1f) == 0x1c) { | 
|  | 1514 | /* read-only integer array */ | 
|  | 1515 | long_tmp = vars[variable_id] + | 
|  | 1516 | (index * sizeof(long)); | 
|  | 1517 | stack[stack_ptr - 1] = | 
|  | 1518 | get_unaligned_be32(&p[long_tmp]); | 
|  | 1519 | } else | 
|  | 1520 | status = -ERANGE; | 
|  | 1521 |  | 
|  | 1522 | break; | 
|  | 1523 | case OP_PSHA: | 
|  | 1524 | /* | 
|  | 1525 | * Push Boolean array | 
|  | 1526 | * ...argument 0 is variable ID | 
|  | 1527 | * ...stack 0 is count | 
|  | 1528 | * ...stack 1 is array index | 
|  | 1529 | */ | 
|  | 1530 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1531 | break; | 
|  | 1532 | variable_id = args[0]; | 
|  | 1533 |  | 
|  | 1534 | /* check that variable is a Boolean array */ | 
|  | 1535 | if ((attrs[variable_id] & 0x18) != 0x08) { | 
|  | 1536 | status = -ERANGE; | 
|  | 1537 | break; | 
|  | 1538 | } | 
|  | 1539 |  | 
|  | 1540 | charptr_tmp = (u8 *)vars[variable_id]; | 
|  | 1541 |  | 
|  | 1542 | /* pop the count (number of bits to copy) */ | 
|  | 1543 | count = stack[--stack_ptr]; | 
|  | 1544 |  | 
|  | 1545 | /* pop the array index */ | 
|  | 1546 | index = stack[stack_ptr - 1]; | 
|  | 1547 |  | 
|  | 1548 | if (version > 0) | 
|  | 1549 | /* | 
|  | 1550 | * stack 0 = array right index | 
|  | 1551 | * stack 1 = array left index | 
|  | 1552 | */ | 
|  | 1553 | count = 1 + count - index; | 
|  | 1554 |  | 
|  | 1555 | if ((count < 1) || (count > 32)) { | 
|  | 1556 | status = -ERANGE; | 
|  | 1557 | break; | 
|  | 1558 | } | 
|  | 1559 |  | 
|  | 1560 | long_tmp = 0L; | 
|  | 1561 |  | 
|  | 1562 | for (i = 0; i < count; ++i) | 
|  | 1563 | if (charptr_tmp[(i + index) >> 3] & | 
|  | 1564 | (1 << ((i + index) & 7))) | 
|  | 1565 | long_tmp |= (1L << i); | 
|  | 1566 |  | 
|  | 1567 | stack[stack_ptr - 1] = long_tmp; | 
|  | 1568 |  | 
|  | 1569 | break; | 
|  | 1570 | case OP_DYNA: | 
|  | 1571 | /* | 
|  | 1572 | * Dynamically change size of array | 
|  | 1573 | * ...argument 0 is variable ID | 
|  | 1574 | * ...stack 0 is new size | 
|  | 1575 | */ | 
|  | 1576 | if (!altera_check_stack(stack_ptr, 1, &status)) | 
|  | 1577 | break; | 
|  | 1578 | variable_id = args[0]; | 
|  | 1579 | long_tmp = stack[--stack_ptr]; | 
|  | 1580 |  | 
|  | 1581 | if (long_tmp > var_size[variable_id]) { | 
|  | 1582 | var_size[variable_id] = long_tmp; | 
|  | 1583 |  | 
|  | 1584 | if (attrs[variable_id] & 0x10) | 
|  | 1585 | /* allocate integer array */ | 
|  | 1586 | long_tmp *= sizeof(long); | 
|  | 1587 | else | 
|  | 1588 | /* allocate Boolean array */ | 
|  | 1589 | long_tmp = (long_tmp + 7) >> 3; | 
|  | 1590 |  | 
|  | 1591 | /* | 
|  | 1592 | * If the buffer was previously allocated, | 
|  | 1593 | * free it | 
|  | 1594 | */ | 
|  | 1595 | if (attrs[variable_id] & 0x80) { | 
|  | 1596 | kfree((void *)vars[variable_id]); | 
|  | 1597 | vars[variable_id] = 0; | 
|  | 1598 | } | 
|  | 1599 |  | 
|  | 1600 | /* | 
|  | 1601 | * Allocate a new buffer | 
|  | 1602 | * of the requested size | 
|  | 1603 | */ | 
|  | 1604 | vars[variable_id] = (long) | 
|  | 1605 | kzalloc(long_tmp, GFP_KERNEL); | 
|  | 1606 |  | 
|  | 1607 | if (vars[variable_id] == 0) { | 
|  | 1608 | status = -ENOMEM; | 
|  | 1609 | break; | 
|  | 1610 | } | 
|  | 1611 |  | 
|  | 1612 | /* | 
|  | 1613 | * Set the attribute bit to indicate that | 
|  | 1614 | * this buffer was dynamically allocated and | 
|  | 1615 | * should be freed later | 
|  | 1616 | */ | 
|  | 1617 | attrs[variable_id] |= 0x80; | 
|  | 1618 |  | 
|  | 1619 | /* zero out memory */ | 
|  | 1620 | count = ((var_size[variable_id] + 7L) / | 
|  | 1621 | 8L); | 
|  | 1622 | charptr_tmp = (u8 *)(vars[variable_id]); | 
|  | 1623 | for (index = 0; index < count; ++index) | 
|  | 1624 | charptr_tmp[index] = 0; | 
|  | 1625 |  | 
|  | 1626 | } | 
|  | 1627 |  | 
|  | 1628 | break; | 
|  | 1629 | case OP_EXPV: | 
|  | 1630 | /* | 
|  | 1631 | * Export Boolean array | 
|  | 1632 | * ...argument 0 is string ID | 
|  | 1633 | * ...stack 0 is variable ID | 
|  | 1634 | * ...stack 1 is array right index | 
|  | 1635 | * ...stack 2 is array left index | 
|  | 1636 | */ | 
|  | 1637 | if (!altera_check_stack(stack_ptr, 3, &status)) | 
|  | 1638 | break; | 
|  | 1639 | if (version == 0) { | 
|  | 1640 | /* EXPV is not supported in JBC 1.0 */ | 
|  | 1641 | bad_opcode = 1; | 
|  | 1642 | break; | 
|  | 1643 | } | 
|  | 1644 | name = &p[str_table + args[0]]; | 
|  | 1645 | variable_id = stack[--stack_ptr]; | 
|  | 1646 | long_idx = stack[--stack_ptr];/* right indx */ | 
|  | 1647 | long_idx2 = stack[--stack_ptr];/* left indx */ | 
|  | 1648 |  | 
|  | 1649 | if (long_idx > long_idx2) { | 
|  | 1650 | /* reverse indices not supported */ | 
|  | 1651 | status = -ERANGE; | 
|  | 1652 | break; | 
|  | 1653 | } | 
|  | 1654 |  | 
|  | 1655 | long_count = 1 + long_idx2 - long_idx; | 
|  | 1656 |  | 
|  | 1657 | charptr_tmp = (u8 *)vars[variable_id]; | 
|  | 1658 | charptr_tmp2 = NULL; | 
|  | 1659 |  | 
|  | 1660 | if ((long_idx & 7L) != 0) { | 
|  | 1661 | s32 k = long_idx; | 
|  | 1662 | charptr_tmp2 = | 
|  | 1663 | kzalloc(((long_count + 7L) / 8L), | 
|  | 1664 | GFP_KERNEL); | 
|  | 1665 | if (charptr_tmp2 == NULL) { | 
|  | 1666 | status = -ENOMEM; | 
|  | 1667 | break; | 
|  | 1668 | } | 
|  | 1669 |  | 
|  | 1670 | for (i = 0; i < long_count; ++i) { | 
|  | 1671 | if (charptr_tmp[k >> 3] & | 
|  | 1672 | (1 << (k & 7))) | 
|  | 1673 | charptr_tmp2[i >> 3] |= | 
|  | 1674 | (1 << (i & 7)); | 
|  | 1675 | else | 
|  | 1676 | charptr_tmp2[i >> 3] &= | 
|  | 1677 | ~(1 << (i & 7)); | 
|  | 1678 |  | 
|  | 1679 | ++k; | 
|  | 1680 | } | 
|  | 1681 | charptr_tmp = charptr_tmp2; | 
|  | 1682 |  | 
|  | 1683 | } else if (long_idx != 0) | 
|  | 1684 | charptr_tmp = &charptr_tmp[long_idx >> 3]; | 
|  | 1685 |  | 
|  | 1686 | altera_export_bool_array(name, charptr_tmp, | 
|  | 1687 | long_count); | 
|  | 1688 |  | 
|  | 1689 | /* free allocated buffer */ | 
|  | 1690 | if ((long_idx & 7L) != 0) | 
|  | 1691 | kfree(charptr_tmp2); | 
|  | 1692 |  | 
|  | 1693 | break; | 
|  | 1694 | case OP_COPY: { | 
|  | 1695 | /* | 
|  | 1696 | * Array copy | 
|  | 1697 | * ...argument 0 is dest ID | 
|  | 1698 | * ...argument 1 is source ID | 
|  | 1699 | * ...stack 0 is count | 
|  | 1700 | * ...stack 1 is dest index | 
|  | 1701 | * ...stack 2 is source index | 
|  | 1702 | */ | 
|  | 1703 | s32 copy_count; | 
|  | 1704 | s32 copy_index; | 
|  | 1705 | s32 copy_index2; | 
|  | 1706 | s32 destleft; | 
|  | 1707 | s32 src_count; | 
|  | 1708 | s32 dest_count; | 
|  | 1709 | int src_reverse = 0; | 
|  | 1710 | int dest_reverse = 0; | 
|  | 1711 |  | 
|  | 1712 | if (!altera_check_stack(stack_ptr, 3, &status)) | 
|  | 1713 | break; | 
|  | 1714 |  | 
|  | 1715 | copy_count = stack[--stack_ptr]; | 
|  | 1716 | copy_index = stack[--stack_ptr]; | 
|  | 1717 | copy_index2 = stack[--stack_ptr]; | 
|  | 1718 | reverse = 0; | 
|  | 1719 |  | 
|  | 1720 | if (version > 0) { | 
|  | 1721 | /* | 
|  | 1722 | * stack 0 = source right index | 
|  | 1723 | * stack 1 = source left index | 
|  | 1724 | * stack 2 = destination right index | 
|  | 1725 | * stack 3 = destination left index | 
|  | 1726 | */ | 
|  | 1727 | destleft = stack[--stack_ptr]; | 
|  | 1728 |  | 
|  | 1729 | if (copy_count > copy_index) { | 
|  | 1730 | src_reverse = 1; | 
|  | 1731 | reverse = 1; | 
|  | 1732 | src_count = 1 + copy_count - copy_index; | 
|  | 1733 | /* copy_index = source start index */ | 
|  | 1734 | } else { | 
|  | 1735 | src_count = 1 + copy_index - copy_count; | 
|  | 1736 | /* source start index */ | 
|  | 1737 | copy_index = copy_count; | 
|  | 1738 | } | 
|  | 1739 |  | 
|  | 1740 | if (copy_index2 > destleft) { | 
|  | 1741 | dest_reverse = 1; | 
|  | 1742 | reverse = !reverse; | 
|  | 1743 | dest_count = 1 + copy_index2 - destleft; | 
|  | 1744 | /* destination start index */ | 
|  | 1745 | copy_index2 = destleft; | 
|  | 1746 | } else | 
|  | 1747 | dest_count = 1 + destleft - copy_index2; | 
|  | 1748 |  | 
|  | 1749 | copy_count = (src_count < dest_count) ? | 
|  | 1750 | src_count : dest_count; | 
|  | 1751 |  | 
|  | 1752 | if ((src_reverse || dest_reverse) && | 
|  | 1753 | (src_count != dest_count)) | 
|  | 1754 | /* | 
|  | 1755 | * If either the source or destination | 
|  | 1756 | * is reversed, we can't tolerate | 
|  | 1757 | * a length mismatch, because we | 
|  | 1758 | * "left justify" arrays when copying. | 
|  | 1759 | * This won't work correctly | 
|  | 1760 | * with reversed arrays. | 
|  | 1761 | */ | 
|  | 1762 | status = -ERANGE; | 
|  | 1763 |  | 
|  | 1764 | } | 
|  | 1765 |  | 
|  | 1766 | count = copy_count; | 
|  | 1767 | index = copy_index; | 
|  | 1768 | index2 = copy_index2; | 
|  | 1769 |  | 
|  | 1770 | /* | 
|  | 1771 | * If destination is a read-only array, | 
|  | 1772 | * allocate a buffer and convert it to a writable array | 
|  | 1773 | */ | 
|  | 1774 | variable_id = args[1]; | 
|  | 1775 | if ((version > 0) && | 
|  | 1776 | ((attrs[variable_id] & 0x9c) == 0x0c)) { | 
|  | 1777 | /* Allocate a writable buffer for this array */ | 
|  | 1778 | long_tmp = | 
|  | 1779 | (var_size[variable_id] + 7L) >> 3L; | 
|  | 1780 | charptr_tmp2 = (u8 *)vars[variable_id]; | 
|  | 1781 | charptr_tmp = | 
|  | 1782 | kzalloc(long_tmp, GFP_KERNEL); | 
|  | 1783 | vars[variable_id] = (long)charptr_tmp; | 
|  | 1784 |  | 
|  | 1785 | if (vars[variable_id] == 0) { | 
|  | 1786 | status = -ENOMEM; | 
|  | 1787 | break; | 
|  | 1788 | } | 
|  | 1789 |  | 
|  | 1790 | /* zero the buffer */ | 
|  | 1791 | for (long_idx = 0L; long_idx < long_tmp; | 
|  | 1792 | ++long_idx) | 
|  | 1793 | charptr_tmp[long_idx] = 0; | 
|  | 1794 |  | 
|  | 1795 | /* copy previous contents into buffer */ | 
|  | 1796 | for (long_idx = 0L; | 
|  | 1797 | long_idx < var_size[variable_id]; | 
|  | 1798 | ++long_idx) { | 
|  | 1799 | long_idx2 = long_idx; | 
|  | 1800 |  | 
|  | 1801 | if (charptr_tmp2[long_idx2 >> 3] & | 
|  | 1802 | (1 << (long_idx2 & 7))) | 
|  | 1803 | charptr_tmp[long_idx >> 3] |= | 
|  | 1804 | (1 << (long_idx & 7)); | 
|  | 1805 |  | 
|  | 1806 | } | 
|  | 1807 |  | 
|  | 1808 | /* | 
|  | 1809 | set bit 7 - buffer was dynamically allocated */ | 
|  | 1810 | attrs[variable_id] |= 0x80; | 
|  | 1811 |  | 
|  | 1812 | /* clear bit 2 - variable is writable */ | 
|  | 1813 | attrs[variable_id] &= ~0x04; | 
|  | 1814 | attrs[variable_id] |= 0x01; | 
|  | 1815 | } | 
|  | 1816 |  | 
|  | 1817 | charptr_tmp = (u8 *)vars[args[1]]; | 
|  | 1818 | charptr_tmp2 = (u8 *)vars[args[0]]; | 
|  | 1819 |  | 
|  | 1820 | /* check if destination is a writable Boolean array */ | 
|  | 1821 | if ((attrs[args[1]] & 0x1c) != 0x08) { | 
|  | 1822 | status = -ERANGE; | 
|  | 1823 | break; | 
|  | 1824 | } | 
|  | 1825 |  | 
|  | 1826 | if (count < 1) { | 
|  | 1827 | status = -ERANGE; | 
|  | 1828 | break; | 
|  | 1829 | } | 
|  | 1830 |  | 
|  | 1831 | if (reverse) | 
|  | 1832 | index2 += (count - 1); | 
|  | 1833 |  | 
|  | 1834 | for (i = 0; i < count; ++i) { | 
|  | 1835 | if (charptr_tmp2[index >> 3] & | 
|  | 1836 | (1 << (index & 7))) | 
|  | 1837 | charptr_tmp[index2 >> 3] |= | 
|  | 1838 | (1 << (index2 & 7)); | 
|  | 1839 | else | 
|  | 1840 | charptr_tmp[index2 >> 3] &= | 
|  | 1841 | ~(1 << (index2 & 7)); | 
|  | 1842 |  | 
|  | 1843 | ++index; | 
|  | 1844 | if (reverse) | 
|  | 1845 | --index2; | 
|  | 1846 | else | 
|  | 1847 | ++index2; | 
|  | 1848 | } | 
|  | 1849 |  | 
|  | 1850 | break; | 
|  | 1851 | } | 
|  | 1852 | case OP_DSC: | 
|  | 1853 | case OP_ISC: { | 
|  | 1854 | /* | 
|  | 1855 | * DRSCAN with capture | 
|  | 1856 | * IRSCAN with capture | 
|  | 1857 | * ...argument 0 is scan data variable ID | 
|  | 1858 | * ...argument 1 is capture variable ID | 
|  | 1859 | * ...stack 0 is capture index | 
|  | 1860 | * ...stack 1 is scan data index | 
|  | 1861 | * ...stack 2 is count | 
|  | 1862 | */ | 
|  | 1863 | s32 scan_right, scan_left; | 
|  | 1864 | s32 capture_count = 0; | 
|  | 1865 | s32 scan_count = 0; | 
|  | 1866 | s32 capture_index; | 
|  | 1867 | s32 scan_index; | 
|  | 1868 |  | 
|  | 1869 | if (!altera_check_stack(stack_ptr, 3, &status)) | 
|  | 1870 | break; | 
|  | 1871 |  | 
|  | 1872 | capture_index = stack[--stack_ptr]; | 
|  | 1873 | scan_index = stack[--stack_ptr]; | 
|  | 1874 |  | 
|  | 1875 | if (version > 0) { | 
|  | 1876 | /* | 
|  | 1877 | * stack 0 = capture right index | 
|  | 1878 | * stack 1 = capture left index | 
|  | 1879 | * stack 2 = scan right index | 
|  | 1880 | * stack 3 = scan left index | 
|  | 1881 | * stack 4 = count | 
|  | 1882 | */ | 
|  | 1883 | scan_right = stack[--stack_ptr]; | 
|  | 1884 | scan_left = stack[--stack_ptr]; | 
|  | 1885 | capture_count = 1 + scan_index - capture_index; | 
|  | 1886 | scan_count = 1 + scan_left - scan_right; | 
|  | 1887 | scan_index = scan_right; | 
|  | 1888 | } | 
|  | 1889 |  | 
|  | 1890 | long_count = stack[--stack_ptr]; | 
|  | 1891 | /* | 
|  | 1892 | * If capture array is read-only, allocate a buffer | 
|  | 1893 | * and convert it to a writable array | 
|  | 1894 | */ | 
|  | 1895 | variable_id = args[1]; | 
|  | 1896 | if ((version > 0) && | 
|  | 1897 | ((attrs[variable_id] & 0x9c) == 0x0c)) { | 
|  | 1898 | /* Allocate a writable buffer for this array */ | 
|  | 1899 | long_tmp = | 
|  | 1900 | (var_size[variable_id] + 7L) >> 3L; | 
|  | 1901 | charptr_tmp2 = (u8 *)vars[variable_id]; | 
|  | 1902 | charptr_tmp = | 
|  | 1903 | kzalloc(long_tmp, GFP_KERNEL); | 
|  | 1904 | vars[variable_id] = (long)charptr_tmp; | 
|  | 1905 |  | 
|  | 1906 | if (vars[variable_id] == 0) { | 
|  | 1907 | status = -ENOMEM; | 
|  | 1908 | break; | 
|  | 1909 | } | 
|  | 1910 |  | 
|  | 1911 | /* zero the buffer */ | 
|  | 1912 | for (long_idx = 0L; long_idx < long_tmp; | 
|  | 1913 | ++long_idx) | 
|  | 1914 | charptr_tmp[long_idx] = 0; | 
|  | 1915 |  | 
|  | 1916 | /* copy previous contents into buffer */ | 
|  | 1917 | for (long_idx = 0L; | 
|  | 1918 | long_idx < var_size[variable_id]; | 
|  | 1919 | ++long_idx) { | 
|  | 1920 | long_idx2 = long_idx; | 
|  | 1921 |  | 
|  | 1922 | if (charptr_tmp2[long_idx2 >> 3] & | 
|  | 1923 | (1 << (long_idx2 & 7))) | 
|  | 1924 | charptr_tmp[long_idx >> 3] |= | 
|  | 1925 | (1 << (long_idx & 7)); | 
|  | 1926 |  | 
|  | 1927 | } | 
|  | 1928 |  | 
|  | 1929 | /* | 
|  | 1930 | * set bit 7 - buffer was | 
|  | 1931 | * dynamically allocated | 
|  | 1932 | */ | 
|  | 1933 | attrs[variable_id] |= 0x80; | 
|  | 1934 |  | 
|  | 1935 | /* clear bit 2 - variable is writable */ | 
|  | 1936 | attrs[variable_id] &= ~0x04; | 
|  | 1937 | attrs[variable_id] |= 0x01; | 
|  | 1938 |  | 
|  | 1939 | } | 
|  | 1940 |  | 
|  | 1941 | charptr_tmp = (u8 *)vars[args[0]]; | 
|  | 1942 | charptr_tmp2 = (u8 *)vars[args[1]]; | 
|  | 1943 |  | 
|  | 1944 | if ((version > 0) && | 
|  | 1945 | ((long_count > capture_count) || | 
|  | 1946 | (long_count > scan_count))) { | 
|  | 1947 | status = -ERANGE; | 
|  | 1948 | break; | 
|  | 1949 | } | 
|  | 1950 |  | 
|  | 1951 | /* | 
|  | 1952 | * check that capture array | 
|  | 1953 | * is a writable Boolean array | 
|  | 1954 | */ | 
|  | 1955 | if ((attrs[args[1]] & 0x1c) != 0x08) { | 
|  | 1956 | status = -ERANGE; | 
|  | 1957 | break; | 
|  | 1958 | } | 
|  | 1959 |  | 
|  | 1960 | if (status == 0) { | 
|  | 1961 | if (opcode == 0x82) /* DSC */ | 
|  | 1962 | status = altera_swap_dr(astate, | 
|  | 1963 | long_count, | 
|  | 1964 | charptr_tmp, | 
|  | 1965 | scan_index, | 
|  | 1966 | charptr_tmp2, | 
|  | 1967 | capture_index); | 
|  | 1968 | else /* ISC */ | 
|  | 1969 | status = altera_swap_ir(astate, | 
|  | 1970 | long_count, | 
|  | 1971 | charptr_tmp, | 
|  | 1972 | scan_index, | 
|  | 1973 | charptr_tmp2, | 
|  | 1974 | capture_index); | 
|  | 1975 |  | 
|  | 1976 | } | 
|  | 1977 |  | 
|  | 1978 | break; | 
|  | 1979 | } | 
|  | 1980 | case OP_WAIT: | 
|  | 1981 | /* | 
|  | 1982 | * WAIT | 
|  | 1983 | * ...argument 0 is wait state | 
|  | 1984 | * ...argument 1 is end state | 
|  | 1985 | * ...stack 0 is cycles | 
|  | 1986 | * ...stack 1 is microseconds | 
|  | 1987 | */ | 
|  | 1988 | if (!altera_check_stack(stack_ptr, 2, &status)) | 
|  | 1989 | break; | 
|  | 1990 | long_tmp = stack[--stack_ptr]; | 
|  | 1991 |  | 
|  | 1992 | if (long_tmp != 0L) | 
|  | 1993 | status = altera_wait_cycles(astate, long_tmp, | 
|  | 1994 | args[0]); | 
|  | 1995 |  | 
|  | 1996 | long_tmp = stack[--stack_ptr]; | 
|  | 1997 |  | 
|  | 1998 | if ((status == 0) && (long_tmp != 0L)) | 
|  | 1999 | status = altera_wait_msecs(astate, | 
|  | 2000 | long_tmp, | 
|  | 2001 | args[0]); | 
|  | 2002 |  | 
|  | 2003 | if ((status == 0) && (args[1] != args[0])) | 
|  | 2004 | status = altera_goto_jstate(astate, | 
|  | 2005 | args[1]); | 
|  | 2006 |  | 
|  | 2007 | if (version > 0) { | 
|  | 2008 | --stack_ptr; /* throw away MAX cycles */ | 
|  | 2009 | --stack_ptr; /* throw away MAX microseconds */ | 
|  | 2010 | } | 
|  | 2011 | break; | 
|  | 2012 | case OP_CMPA: { | 
|  | 2013 | /* | 
|  | 2014 | * Array compare | 
|  | 2015 | * ...argument 0 is source 1 ID | 
|  | 2016 | * ...argument 1 is source 2 ID | 
|  | 2017 | * ...argument 2 is mask ID | 
|  | 2018 | * ...stack 0 is source 1 index | 
|  | 2019 | * ...stack 1 is source 2 index | 
|  | 2020 | * ...stack 2 is mask index | 
|  | 2021 | * ...stack 3 is count | 
|  | 2022 | */ | 
|  | 2023 | s32 a, b; | 
|  | 2024 | u8 *source1 = (u8 *)vars[args[0]]; | 
|  | 2025 | u8 *source2 = (u8 *)vars[args[1]]; | 
|  | 2026 | u8 *mask = (u8 *)vars[args[2]]; | 
|  | 2027 | u32 index1; | 
|  | 2028 | u32 index2; | 
|  | 2029 | u32 mask_index; | 
|  | 2030 |  | 
|  | 2031 | if (!altera_check_stack(stack_ptr, 4, &status)) | 
|  | 2032 | break; | 
|  | 2033 |  | 
|  | 2034 | index1 = stack[--stack_ptr]; | 
|  | 2035 | index2 = stack[--stack_ptr]; | 
|  | 2036 | mask_index = stack[--stack_ptr]; | 
|  | 2037 | long_count = stack[--stack_ptr]; | 
|  | 2038 |  | 
|  | 2039 | if (version > 0) { | 
|  | 2040 | /* | 
|  | 2041 | * stack 0 = source 1 right index | 
|  | 2042 | * stack 1 = source 1 left index | 
|  | 2043 | * stack 2 = source 2 right index | 
|  | 2044 | * stack 3 = source 2 left index | 
|  | 2045 | * stack 4 = mask right index | 
|  | 2046 | * stack 5 = mask left index | 
|  | 2047 | */ | 
|  | 2048 | s32 mask_right = stack[--stack_ptr]; | 
|  | 2049 | s32 mask_left = stack[--stack_ptr]; | 
|  | 2050 | /* source 1 count */ | 
|  | 2051 | a = 1 + index2 - index1; | 
|  | 2052 | /* source 2 count */ | 
|  | 2053 | b = 1 + long_count - mask_index; | 
|  | 2054 | a = (a < b) ? a : b; | 
|  | 2055 | /* mask count */ | 
|  | 2056 | b = 1 + mask_left - mask_right; | 
|  | 2057 | a = (a < b) ? a : b; | 
|  | 2058 | /* source 2 start index */ | 
|  | 2059 | index2 = mask_index; | 
|  | 2060 | /* mask start index */ | 
|  | 2061 | mask_index = mask_right; | 
|  | 2062 | long_count = a; | 
|  | 2063 | } | 
|  | 2064 |  | 
|  | 2065 | long_tmp = 1L; | 
|  | 2066 |  | 
|  | 2067 | if (long_count < 1) | 
|  | 2068 | status = -ERANGE; | 
|  | 2069 | else { | 
|  | 2070 | count = long_count; | 
|  | 2071 |  | 
|  | 2072 | for (i = 0; i < count; ++i) { | 
|  | 2073 | if (mask[mask_index >> 3] & | 
|  | 2074 | (1 << (mask_index & 7))) { | 
|  | 2075 | a = source1[index1 >> 3] & | 
|  | 2076 | (1 << (index1 & 7)) | 
|  | 2077 | ? 1 : 0; | 
|  | 2078 | b = source2[index2 >> 3] & | 
|  | 2079 | (1 << (index2 & 7)) | 
|  | 2080 | ? 1 : 0; | 
|  | 2081 |  | 
|  | 2082 | if (a != b) /* failure */ | 
|  | 2083 | long_tmp = 0L; | 
|  | 2084 | } | 
|  | 2085 | ++index1; | 
|  | 2086 | ++index2; | 
|  | 2087 | ++mask_index; | 
|  | 2088 | } | 
|  | 2089 | } | 
|  | 2090 |  | 
|  | 2091 | stack[stack_ptr++] = long_tmp; | 
|  | 2092 |  | 
|  | 2093 | break; | 
|  | 2094 | } | 
|  | 2095 | default: | 
|  | 2096 | /* Unrecognized opcode -- ERROR! */ | 
|  | 2097 | bad_opcode = 1; | 
|  | 2098 | break; | 
|  | 2099 | } | 
|  | 2100 |  | 
|  | 2101 | if (bad_opcode) | 
|  | 2102 | status = -ENOSYS; | 
|  | 2103 |  | 
|  | 2104 | if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE)) | 
|  | 2105 | status = -EOVERFLOW; | 
|  | 2106 |  | 
|  | 2107 | if (status != 0) { | 
|  | 2108 | done = 1; | 
|  | 2109 | *error_address = (s32)(opcode_address - code_sect); | 
|  | 2110 | } | 
|  | 2111 | } | 
|  | 2112 |  | 
|  | 2113 | altera_free_buffers(astate); | 
|  | 2114 |  | 
|  | 2115 | /* Free all dynamically allocated arrays */ | 
|  | 2116 | if ((attrs != NULL) && (vars != NULL)) | 
|  | 2117 | for (i = 0; i < sym_count; ++i) | 
|  | 2118 | if (attrs[i] & 0x80) | 
|  | 2119 | kfree((void *)vars[i]); | 
|  | 2120 |  | 
|  | 2121 | kfree(vars); | 
|  | 2122 | kfree(var_size); | 
|  | 2123 | kfree(attrs); | 
|  | 2124 | kfree(proc_attributes); | 
|  | 2125 |  | 
|  | 2126 | return status; | 
|  | 2127 | } | 
|  | 2128 |  | 
|  | 2129 | static int altera_get_note(u8 *p, s32 program_size, | 
|  | 2130 | s32 *offset, char *key, char *value, int length) | 
|  | 2131 | /* | 
|  | 2132 | * Gets key and value of NOTE fields in the JBC file. | 
|  | 2133 | * Can be called in two modes:  if offset pointer is NULL, | 
|  | 2134 | * then the function searches for note fields which match | 
|  | 2135 | * the key string provided.  If offset is not NULL, then | 
|  | 2136 | * the function finds the next note field of any key, | 
|  | 2137 | * starting at the offset specified by the offset pointer. | 
|  | 2138 | * Returns 0 for success, else appropriate error code | 
|  | 2139 | */ | 
|  | 2140 | { | 
|  | 2141 | int status = -ENODATA; | 
|  | 2142 | u32 note_strings = 0L; | 
|  | 2143 | u32 note_table = 0L; | 
|  | 2144 | u32 note_count = 0L; | 
|  | 2145 | u32 first_word = 0L; | 
|  | 2146 | int version = 0; | 
|  | 2147 | int delta = 0; | 
|  | 2148 | char *key_ptr; | 
|  | 2149 | char *value_ptr; | 
|  | 2150 | int i; | 
|  | 2151 |  | 
|  | 2152 | /* Read header information */ | 
|  | 2153 | if (program_size > 52L) { | 
|  | 2154 | first_word    = get_unaligned_be32(&p[0]); | 
|  | 2155 | version = (first_word & 1L); | 
|  | 2156 | delta = version * 8; | 
|  | 2157 |  | 
|  | 2158 | note_strings  = get_unaligned_be32(&p[8 + delta]); | 
|  | 2159 | note_table    = get_unaligned_be32(&p[12 + delta]); | 
|  | 2160 | note_count    = get_unaligned_be32(&p[44 + (2 * delta)]); | 
|  | 2161 | } | 
|  | 2162 |  | 
|  | 2163 | if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) | 
|  | 2164 | return -EIO; | 
|  | 2165 |  | 
|  | 2166 | if (note_count <= 0L) | 
|  | 2167 | return status; | 
|  | 2168 |  | 
|  | 2169 | if (offset == NULL) { | 
|  | 2170 | /* | 
|  | 2171 | * We will search for the first note with a specific key, | 
|  | 2172 | * and return only the value | 
|  | 2173 | */ | 
|  | 2174 | for (i = 0; (i < note_count) && | 
|  | 2175 | (status != 0); ++i) { | 
|  | 2176 | key_ptr = &p[note_strings + | 
|  | 2177 | get_unaligned_be32( | 
|  | 2178 | &p[note_table + (8 * i)])]; | 
|  | 2179 | if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) && | 
|  | 2180 | (key != NULL)) { | 
|  | 2181 | status = 0; | 
|  | 2182 |  | 
|  | 2183 | value_ptr = &p[note_strings + | 
|  | 2184 | get_unaligned_be32( | 
|  | 2185 | &p[note_table + (8 * i) + 4])]; | 
|  | 2186 |  | 
|  | 2187 | if (value != NULL) | 
|  | 2188 | strlcpy(value, value_ptr, length); | 
|  | 2189 |  | 
|  | 2190 | } | 
|  | 2191 | } | 
|  | 2192 | } else { | 
|  | 2193 | /* | 
|  | 2194 | * We will search for the next note, regardless of the key, | 
|  | 2195 | * and return both the value and the key | 
|  | 2196 | */ | 
|  | 2197 |  | 
|  | 2198 | i = *offset; | 
|  | 2199 |  | 
|  | 2200 | if ((i >= 0) && (i < note_count)) { | 
|  | 2201 | status = 0; | 
|  | 2202 |  | 
|  | 2203 | if (key != NULL) | 
|  | 2204 | strlcpy(key, &p[note_strings + | 
|  | 2205 | get_unaligned_be32( | 
|  | 2206 | &p[note_table + (8 * i)])], | 
|  | 2207 | length); | 
|  | 2208 |  | 
|  | 2209 | if (value != NULL) | 
|  | 2210 | strlcpy(value, &p[note_strings + | 
|  | 2211 | get_unaligned_be32( | 
|  | 2212 | &p[note_table + (8 * i) + 4])], | 
|  | 2213 | length); | 
|  | 2214 |  | 
|  | 2215 | *offset = i + 1; | 
|  | 2216 | } | 
|  | 2217 | } | 
|  | 2218 |  | 
|  | 2219 | return status; | 
|  | 2220 | } | 
|  | 2221 |  | 
|  | 2222 | static int altera_check_crc(u8 *p, s32 program_size) | 
|  | 2223 | { | 
|  | 2224 | int status = 0; | 
|  | 2225 | u16 local_expected = 0, | 
|  | 2226 | local_actual = 0, | 
|  | 2227 | shift_reg = 0xffff; | 
|  | 2228 | int bit, feedback; | 
|  | 2229 | u8 databyte; | 
|  | 2230 | u32 i; | 
|  | 2231 | u32 crc_section = 0L; | 
|  | 2232 | u32 first_word = 0L; | 
|  | 2233 | int version = 0; | 
|  | 2234 | int delta = 0; | 
|  | 2235 |  | 
|  | 2236 | if (program_size > 52L) { | 
|  | 2237 | first_word  = get_unaligned_be32(&p[0]); | 
|  | 2238 | version = (first_word & 1L); | 
|  | 2239 | delta = version * 8; | 
|  | 2240 |  | 
|  | 2241 | crc_section = get_unaligned_be32(&p[32 + delta]); | 
|  | 2242 | } | 
|  | 2243 |  | 
|  | 2244 | if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) | 
|  | 2245 | status = -EIO; | 
|  | 2246 |  | 
|  | 2247 | if (crc_section >= program_size) | 
|  | 2248 | status = -EIO; | 
|  | 2249 |  | 
|  | 2250 | if (status == 0) { | 
|  | 2251 | local_expected = (u16)get_unaligned_be16(&p[crc_section]); | 
|  | 2252 |  | 
|  | 2253 | for (i = 0; i < crc_section; ++i) { | 
|  | 2254 | databyte = p[i]; | 
|  | 2255 | for (bit = 0; bit < 8; bit++) { | 
|  | 2256 | feedback = (databyte ^ shift_reg) & 0x01; | 
|  | 2257 | shift_reg >>= 1; | 
|  | 2258 | if (feedback) | 
|  | 2259 | shift_reg ^= 0x8408; | 
|  | 2260 |  | 
|  | 2261 | databyte >>= 1; | 
|  | 2262 | } | 
|  | 2263 | } | 
|  | 2264 |  | 
|  | 2265 | local_actual = (u16)~shift_reg; | 
|  | 2266 |  | 
|  | 2267 | if (local_expected != local_actual) | 
|  | 2268 | status = -EILSEQ; | 
|  | 2269 |  | 
|  | 2270 | } | 
|  | 2271 |  | 
|  | 2272 | if (debug || status) { | 
|  | 2273 | switch (status) { | 
|  | 2274 | case 0: | 
|  | 2275 | printk(KERN_INFO "%s: CRC matched: %04x\n", __func__, | 
|  | 2276 | local_actual); | 
|  | 2277 | break; | 
|  | 2278 | case -EILSEQ: | 
|  | 2279 | printk(KERN_ERR "%s: CRC mismatch: expected %04x, " | 
|  | 2280 | "actual %04x\n", __func__, local_expected, | 
|  | 2281 | local_actual); | 
|  | 2282 | break; | 
|  | 2283 | case -ENODATA: | 
|  | 2284 | printk(KERN_ERR "%s: expected CRC not found, " | 
|  | 2285 | "actual CRC = %04x\n", __func__, | 
|  | 2286 | local_actual); | 
|  | 2287 | break; | 
|  | 2288 | case -EIO: | 
|  | 2289 | printk(KERN_ERR "%s: error: format isn't " | 
|  | 2290 | "recognized.\n", __func__); | 
|  | 2291 | break; | 
|  | 2292 | default: | 
|  | 2293 | printk(KERN_ERR "%s: CRC function returned error " | 
|  | 2294 | "code %d\n", __func__, status); | 
|  | 2295 | break; | 
|  | 2296 | } | 
|  | 2297 | } | 
|  | 2298 |  | 
|  | 2299 | return status; | 
|  | 2300 | } | 
|  | 2301 |  | 
|  | 2302 | static int altera_get_file_info(u8 *p, | 
|  | 2303 | s32 program_size, | 
|  | 2304 | int *format_version, | 
|  | 2305 | int *action_count, | 
|  | 2306 | int *procedure_count) | 
|  | 2307 | { | 
|  | 2308 | int status = -EIO; | 
|  | 2309 | u32 first_word = 0; | 
|  | 2310 | int version = 0; | 
|  | 2311 |  | 
|  | 2312 | if (program_size <= 52L) | 
|  | 2313 | return status; | 
|  | 2314 |  | 
|  | 2315 | first_word = get_unaligned_be32(&p[0]); | 
|  | 2316 |  | 
|  | 2317 | if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) { | 
|  | 2318 | status = 0; | 
|  | 2319 |  | 
|  | 2320 | version = (first_word & 1L); | 
|  | 2321 | *format_version = version + 1; | 
|  | 2322 |  | 
|  | 2323 | if (version > 0) { | 
|  | 2324 | *action_count = get_unaligned_be32(&p[48]); | 
|  | 2325 | *procedure_count = get_unaligned_be32(&p[52]); | 
|  | 2326 | } | 
|  | 2327 | } | 
|  | 2328 |  | 
|  | 2329 | return status; | 
|  | 2330 | } | 
|  | 2331 |  | 
|  | 2332 | static int altera_get_act_info(u8 *p, | 
|  | 2333 | s32 program_size, | 
|  | 2334 | int index, | 
|  | 2335 | char **name, | 
|  | 2336 | char **description, | 
|  | 2337 | struct altera_procinfo **proc_list) | 
|  | 2338 | { | 
|  | 2339 | int status = -EIO; | 
|  | 2340 | struct altera_procinfo *procptr = NULL; | 
|  | 2341 | struct altera_procinfo *tmpptr = NULL; | 
|  | 2342 | u32 first_word = 0L; | 
|  | 2343 | u32 action_table = 0L; | 
|  | 2344 | u32 proc_table = 0L; | 
|  | 2345 | u32 str_table = 0L; | 
|  | 2346 | u32 note_strings = 0L; | 
|  | 2347 | u32 action_count = 0L; | 
|  | 2348 | u32 proc_count = 0L; | 
|  | 2349 | u32 act_name_id = 0L; | 
|  | 2350 | u32 act_desc_id = 0L; | 
|  | 2351 | u32 act_proc_id = 0L; | 
|  | 2352 | u32 act_proc_name = 0L; | 
|  | 2353 | u8 act_proc_attribute = 0; | 
|  | 2354 |  | 
|  | 2355 | if (program_size <= 52L) | 
|  | 2356 | return status; | 
|  | 2357 | /* Read header information */ | 
|  | 2358 | first_word = get_unaligned_be32(&p[0]); | 
|  | 2359 |  | 
|  | 2360 | if (first_word != 0x4A414D01L) | 
|  | 2361 | return status; | 
|  | 2362 |  | 
|  | 2363 | action_table = get_unaligned_be32(&p[4]); | 
|  | 2364 | proc_table   = get_unaligned_be32(&p[8]); | 
|  | 2365 | str_table = get_unaligned_be32(&p[12]); | 
|  | 2366 | note_strings = get_unaligned_be32(&p[16]); | 
|  | 2367 | action_count = get_unaligned_be32(&p[48]); | 
|  | 2368 | proc_count   = get_unaligned_be32(&p[52]); | 
|  | 2369 |  | 
|  | 2370 | if (index >= action_count) | 
|  | 2371 | return status; | 
|  | 2372 |  | 
|  | 2373 | act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]); | 
|  | 2374 | act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]); | 
|  | 2375 | act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]); | 
|  | 2376 |  | 
|  | 2377 | *name = &p[str_table + act_name_id]; | 
|  | 2378 |  | 
|  | 2379 | if (act_desc_id < (note_strings - str_table)) | 
|  | 2380 | *description = &p[str_table + act_desc_id]; | 
|  | 2381 |  | 
|  | 2382 | do { | 
|  | 2383 | act_proc_name = get_unaligned_be32( | 
|  | 2384 | &p[proc_table + (13 * act_proc_id)]); | 
|  | 2385 | act_proc_attribute = | 
|  | 2386 | (p[proc_table + (13 * act_proc_id) + 8] & 0x03); | 
|  | 2387 |  | 
| Thomas Meyer | 8c82b13 | 2011-08-13 11:34:09 +0200 | [diff] [blame] | 2388 | procptr = | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2389 | kzalloc(sizeof(struct altera_procinfo), | 
|  | 2390 | GFP_KERNEL); | 
|  | 2391 |  | 
|  | 2392 | if (procptr == NULL) | 
|  | 2393 | status = -ENOMEM; | 
|  | 2394 | else { | 
|  | 2395 | procptr->name = &p[str_table + act_proc_name]; | 
|  | 2396 | procptr->attrs = act_proc_attribute; | 
|  | 2397 | procptr->next = NULL; | 
|  | 2398 |  | 
|  | 2399 | /* add record to end of linked list */ | 
|  | 2400 | if (*proc_list == NULL) | 
|  | 2401 | *proc_list = procptr; | 
|  | 2402 | else { | 
|  | 2403 | tmpptr = *proc_list; | 
|  | 2404 | while (tmpptr->next != NULL) | 
|  | 2405 | tmpptr = tmpptr->next; | 
|  | 2406 | tmpptr->next = procptr; | 
|  | 2407 | } | 
|  | 2408 | } | 
|  | 2409 |  | 
|  | 2410 | act_proc_id = get_unaligned_be32( | 
|  | 2411 | &p[proc_table + (13 * act_proc_id) + 4]); | 
|  | 2412 | } while ((act_proc_id != 0) && (act_proc_id < proc_count)); | 
|  | 2413 |  | 
|  | 2414 | return status; | 
|  | 2415 | } | 
|  | 2416 |  | 
|  | 2417 | int altera_init(struct altera_config *config, const struct firmware *fw) | 
|  | 2418 | { | 
|  | 2419 | struct altera_state *astate = NULL; | 
|  | 2420 | struct altera_procinfo *proc_list = NULL; | 
|  | 2421 | struct altera_procinfo *procptr = NULL; | 
|  | 2422 | char *key = NULL; | 
|  | 2423 | char *value = NULL; | 
|  | 2424 | char *action_name = NULL; | 
|  | 2425 | char *description = NULL; | 
|  | 2426 | int exec_result = 0; | 
|  | 2427 | int exit_code = 0; | 
|  | 2428 | int format_version = 0; | 
|  | 2429 | int action_count = 0; | 
|  | 2430 | int procedure_count = 0; | 
|  | 2431 | int index = 0; | 
|  | 2432 | s32 offset = 0L; | 
|  | 2433 | s32 error_address = 0L; | 
| Peter Huewe | c0777d2 | 2011-05-31 01:11:17 +0200 | [diff] [blame] | 2434 | int retval = 0; | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2435 |  | 
| Peter Huewe | c0777d2 | 2011-05-31 01:11:17 +0200 | [diff] [blame] | 2436 | key = kzalloc(33, GFP_KERNEL); | 
|  | 2437 | if (!key) { | 
|  | 2438 | retval = -ENOMEM; | 
|  | 2439 | goto out; | 
|  | 2440 | } | 
|  | 2441 | value = kzalloc(257, GFP_KERNEL); | 
|  | 2442 | if (!value) { | 
|  | 2443 | retval = -ENOMEM; | 
|  | 2444 | goto free_key; | 
|  | 2445 | } | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2446 | astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL); | 
| Peter Huewe | c0777d2 | 2011-05-31 01:11:17 +0200 | [diff] [blame] | 2447 | if (!astate) { | 
|  | 2448 | retval = -ENOMEM; | 
|  | 2449 | goto free_value; | 
|  | 2450 | } | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2451 |  | 
|  | 2452 | astate->config = config; | 
|  | 2453 | if (!astate->config->jtag_io) { | 
|  | 2454 | dprintk(KERN_INFO "%s: using byteblaster!\n", __func__); | 
|  | 2455 | astate->config->jtag_io = netup_jtag_io_lpt; | 
|  | 2456 | } | 
|  | 2457 |  | 
|  | 2458 | altera_check_crc((u8 *)fw->data, fw->size); | 
|  | 2459 |  | 
|  | 2460 | if (debug) { | 
|  | 2461 | altera_get_file_info((u8 *)fw->data, fw->size, &format_version, | 
|  | 2462 | &action_count, &procedure_count); | 
|  | 2463 | printk(KERN_INFO "%s: File format is %s ByteCode format\n", | 
|  | 2464 | __func__, (format_version == 2) ? "Jam STAPL" : | 
|  | 2465 | "pre-standardized Jam 1.1"); | 
|  | 2466 | while (altera_get_note((u8 *)fw->data, fw->size, | 
|  | 2467 | &offset, key, value, 256) == 0) | 
|  | 2468 | printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", | 
|  | 2469 | __func__, key, value); | 
|  | 2470 | } | 
|  | 2471 |  | 
|  | 2472 | if (debug && (format_version == 2) && (action_count > 0)) { | 
|  | 2473 | printk(KERN_INFO "%s: Actions available:\n", __func__); | 
|  | 2474 | for (index = 0; index < action_count; ++index) { | 
|  | 2475 | altera_get_act_info((u8 *)fw->data, fw->size, | 
|  | 2476 | index, &action_name, | 
|  | 2477 | &description, | 
|  | 2478 | &proc_list); | 
|  | 2479 |  | 
|  | 2480 | if (description == NULL) | 
|  | 2481 | printk(KERN_INFO "%s: %s\n", | 
|  | 2482 | __func__, | 
|  | 2483 | action_name); | 
|  | 2484 | else | 
|  | 2485 | printk(KERN_INFO "%s: %s \"%s\"\n", | 
|  | 2486 | __func__, | 
|  | 2487 | action_name, | 
|  | 2488 | description); | 
|  | 2489 |  | 
|  | 2490 | procptr = proc_list; | 
|  | 2491 | while (procptr != NULL) { | 
|  | 2492 | if (procptr->attrs != 0) | 
|  | 2493 | printk(KERN_INFO "%s:    %s (%s)\n", | 
|  | 2494 | __func__, | 
|  | 2495 | procptr->name, | 
|  | 2496 | (procptr->attrs == 1) ? | 
|  | 2497 | "optional" : "recommended"); | 
|  | 2498 |  | 
|  | 2499 | proc_list = procptr->next; | 
|  | 2500 | kfree(procptr); | 
|  | 2501 | procptr = proc_list; | 
|  | 2502 | } | 
|  | 2503 | } | 
|  | 2504 |  | 
|  | 2505 | printk(KERN_INFO "\n"); | 
|  | 2506 | } | 
|  | 2507 |  | 
|  | 2508 | exec_result = altera_execute(astate, (u8 *)fw->data, fw->size, | 
|  | 2509 | &error_address, &exit_code, &format_version); | 
|  | 2510 |  | 
|  | 2511 | if (exit_code) | 
|  | 2512 | exec_result = -EREMOTEIO; | 
|  | 2513 |  | 
|  | 2514 | if ((format_version == 2) && (exec_result == -EINVAL)) { | 
|  | 2515 | if (astate->config->action == NULL) | 
|  | 2516 | printk(KERN_ERR "%s: error: no action specified for " | 
|  | 2517 | "Jam STAPL file.\nprogram terminated.\n", | 
|  | 2518 | __func__); | 
|  | 2519 | else | 
|  | 2520 | printk(KERN_ERR "%s: error: action \"%s\"" | 
|  | 2521 | " is not supported " | 
|  | 2522 | "for this Jam STAPL file.\n" | 
|  | 2523 | "Program terminated.\n", __func__, | 
|  | 2524 | astate->config->action); | 
|  | 2525 |  | 
|  | 2526 | } else if (exec_result) | 
|  | 2527 | printk(KERN_ERR "%s: error %d\n", __func__, exec_result); | 
|  | 2528 |  | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2529 | kfree(astate); | 
| Peter Huewe | c0777d2 | 2011-05-31 01:11:17 +0200 | [diff] [blame] | 2530 | free_value: | 
|  | 2531 | kfree(value); | 
|  | 2532 | free_key: | 
|  | 2533 | kfree(key); | 
|  | 2534 | out: | 
|  | 2535 | return retval; | 
| Igor M. Liplianin | fa766c9 | 2011-01-25 17:00:00 -0300 | [diff] [blame] | 2536 | } | 
|  | 2537 | EXPORT_SYMBOL(altera_init); |