/* ======================================================================= C25SIM.C - An easy-to-use C25 simulator Copyright (C) 1995 Will Ware This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ======================================================================= */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "conio.h" #include "graph.h" #include "c25lib.h" #include "windows.h" #define X(z) /* ======================================================================= */ /* Defines, Global Variables, Function prototypes */ /* ======================================================================= */ #define READ_BLOCK_WIDTH 8 #define IS_WHITE_SPACE(c) ((c) == ' ' || (c) == '\t') #define ui(x) ((unsigned int) (x)) #define next_link(p) ((char *) *((int *)(p))) #define set_next_link(p,n) *((char **) (p)) = n #define string_part(p) (((char *) (p)) + sizeof(char *)) #define DIVISION 52 #define F1_key 59 #define F2_key 60 #define F3_key 61 #define F4_key 62 #define F5_key 63 #define F6_key 64 #define Page_Up_key 73 #define Page_Down_key 81 #define Home_key 71 #define End_key 79 #define Arrow_Down_key 80 #define Arrow_Up_key 72 char line[80], cvals[40][10], *cv[40], *listing_head, *help_head, listline[100], pre_line[100], name[40], fline[80], dummy2[40], *first_symbol; int cc, pw[20][3], dw[20][3], npw = 0, ndw = 0, listing_window, regular_window, register_window, search_string_window, not_found_window, symbol_table_first_line = 0, listing_first_line = 0, help_first_line = 0, end_file = 0; unsigned int choice, addr, data, c25_background = 0; unsigned long int stop_at; screen_buffer regular, listing; FILE *f; long int get_int(int n); void get_command(void); void quit(void); void do_menu(void); void load_files(void); void write_progmem(void); void read_progmem(void); void write_datamem(void); void read_datamem(void); int modify_known_register(char *name, long int value); void modify_register(void); void breakpoint(void); void go_n(long int r); void go(void); void n_cycles(void); void intrupt(void); void find_matches(void); void toggle_bkgnd(void); int progmem_waits(unsigned int a); int datamem_waits(unsigned int a); void pm_wait_range(void); void dm_wait_range(void); void get_file_line(void); char *add_line(char **head, char *line); void pull_in_file(char **head); void pull_in_listing(void) ; void redisplay_listing(char **head, int *first_line); void alternate_screen(char **head, int *first_line); void load_listing_file(char *word); void load_help_file(void); void load_map_file(char *word); int lookup_symbol(char *name); int print_matching_symbols(int a); int print_all_symbols(void); void make_report(void); void main(int argc, char *argv[]); /* ======================================================================= */ /* Menu Table */ /* ======================================================================= */ typedef struct { char name[10]; void (*func) (void); } menu_entry; menu_entry menu[] = { "load", load_files, "wp", write_progmem, "rp", read_progmem, "wd", write_datamem, "rd", read_datamem, "mr", modify_register, "pwait", pm_wait_range, "dwait", dm_wait_range, "bp", breakpoint, "clrbps", clear_all_breakpoints, "go", go, "cycles", n_cycles, "reset", c25_reset, "bkgnd", toggle_bkgnd, "int", intrupt, "symbols", print_all_symbols, "match?", find_matches, "listing", pull_in_listing, "quit", quit, "", NULL }; /* If you recompile with Borland Turbo C, you may see a warning about a suspicious pointer conversion for go_til_breakpoint(). Generally you don't want to ignore suspicious pointer conversions, but this one is okay. */ /* ======================================================================= */ /* Menu Fun */ /* ======================================================================= */ long int get_int(int n) { long int x; if (cv[n][0] == '0' && toupper(cv[n][1]) == 'X' && (sscanf(cv[n] + 2, "%lx", &x) == 1)) return x; if (sscanf(cv[n], "%ld", &x) == 1) return x; return lookup_symbol(cv[n]); } void get_command(void) { char c; int lptr, cptr; lptr = 0; cptr = 0; cc = 0; while (1) { do { c = line[lptr++]; if (c == '\0') return; } while (IS_WHITE_SPACE(c)); do { cvals[cc][cptr++] = c; c = line[lptr++]; } while (!IS_WHITE_SPACE(c) && (c != '\0')); cvals[cc][cptr] = '\0'; cv[cc] = &cvals[cc][0]; cptr = 0; cc++; if (c == '\0') return; } } void quit(void) { int i; for (i = 0; i < num_windows; i++) clear_n(i); exit(0); } void do_menu(void) { unsigned int i; get_command(); if (cc == 0) return; for (i = 0; strlen(menu[i].name) != 0; i++) if (stricmp(cv[0], menu[i].name) == 0) { (*menu[i].func)(); return; } __write("what?\n"); } /* ======================================================================= */ /* Simulator Functions */ /* ======================================================================= */ void load_files(void) { if (cc < 2) { __write("Usage: load filename\n"); return; } load_hex_files(cvals[1]); load_map_file(cvals[1]); } void write_progmem(void) { if (cc < 3) { __write("Usage: wp addr data\n"); return; } addr = (int) get_int(1); data = (int) get_int(2); *program_memory_address(addr) = data; } void read_progmem(void) { unsigned int i, addr2; if (cc < 2) { __write("Usage: rp addr\n"); return; } __write("Program memory\n"); addr = (int) get_int(1); if (cc > 2) addr2 = (int) get_int(2); else addr2 = addr + 1; for (i = addr; i != addr2; i++) switch ((i - addr) & (READ_BLOCK_WIDTH - 1)) { case 0: sprintf(toprint, "%04X - %04X ", i, *program_memory_address(i)); __write(toprint); break; case READ_BLOCK_WIDTH - 1: sprintf(toprint, "%04X\n", *program_memory_address(i)); __write(toprint); break; default: sprintf(toprint, "%04X ", *program_memory_address(i)); __write(toprint); break; } if (((i - addr) & (READ_BLOCK_WIDTH - 1)) != 0) __write("\n"); } void write_datamem(void) { if (cc < 3) { __write("Usage: wd addr data\n"); return; } addr = (int) get_int(1); data = (int) get_int(2); *data_memory_address(addr) = data; } void read_datamem(void) { unsigned int i, addr2; if (cc < 2) { __write("Usage: rd addr\n"); return; } __write("Data memory\n"); addr = (int) get_int(1); if (cc > 2) addr2 = (int) get_int(2); else addr2 = addr + 1; for (i = addr; i != addr2; i++) switch ((i - addr) & (READ_BLOCK_WIDTH - 1)) { case 0: sprintf(toprint, "%04X - %04X ", i, *data_memory_address(i)); __write(toprint); break; case READ_BLOCK_WIDTH - 1: sprintf(toprint, "%04X\n", *data_memory_address(i)); __write(toprint); break; default: sprintf(toprint, "%04X ", *data_memory_address(i)); __write(toprint); break; } if (((i - addr) & (READ_BLOCK_WIDTH - 1)) != 0) __write("\n"); } int modify_known_register(char *name, long int value) { if (strcmpi(name, "arp") == 0) { arp = (int) value; return 1; } if (strcmpi(name, "ov") == 0) { ov = (int) value; return 1; } if (strcmpi(name, "ovm") == 0) { ovm = (int) value; return 1; } if (strcmpi(name, "intm") == 0) { intm = (int) value; return 1; } if (strcmpi(name, "dp") == 0) { dp = (int) value; return 1; } if (strcmpi(name, "arb") == 0) { arb = (int) value; return 1; } if (strcmpi(name, "cnf") == 0) { cnf = (int) value; return 1; } if (strcmpi(name, "tc") == 0) { tc = (int) value; return 1; } if (strcmpi(name, "sxm") == 0) { sxm = (int) value; return 1; } if (strcmpi(name, "c") == 0) { c = (int) value; return 1; } if (strcmpi(name, "hm") == 0) { hm = (int) value; return 1; } if (strcmpi(name, "fsm") == 0) { fsm = (int) value; return 1; } if (strcmpi(name, "xf") == 0) { xf = (int) value; return 1; } if (strcmpi(name, "fo") == 0) { fo = (int) value; return 1; } if (strcmpi(name, "txm") == 0) { txm = (int) value; return 1; } if (strcmpi(name, "pm") == 0) { pm = (int) value; return 1; } if (strcmpi(name, "pc") == 0) { pc = (int) value; return 1; } if (strcmpi(name, "t") == 0) { t_register = (int) value; return 1; } if (strcmpi(name, "sp") == 0) { _sp = (int) value; return 1; } if (strcmpi(name, "ar0") == 0) { ar[0] = (int) value; return 1; } if (strcmpi(name, "ar1") == 0) { ar[1] = (int) value; return 1; } if (strcmpi(name, "ar2") == 0) { ar[2] = (int) value; return 1; } if (strcmpi(name, "ar3") == 0) { ar[3] = (int) value; return 1; } if (strcmpi(name, "ar4") == 0) { ar[4] = (int) value; return 1; } if (strcmpi(name, "ar5") == 0) { ar[5] = (int) value; return 1; } if (strcmpi(name, "ar6") == 0) { ar[6] = (int) value; return 1; } if (strcmpi(name, "ar7") == 0) { ar[7] = (int) value; return 1; } if (strcmpi(name, "bio") == 0) { bio = (int) value; return 1; } if (strcmpi(name, "acc") == 0) { accumulator = value; return 1; } if (strcmpi(name, "p") == 0) { p_register = value; return 1; } if (strcmpi(name, "drr") == 0) { drr = (int) value; return 1; } if (strcmpi(name, "dxr") == 0) { dxr = (int) value; return 1; } if (strcmpi(name, "tim") == 0) { tim = (int) value; return 1; } if (strcmpi(name, "prd") == 0) { prd = (int) value; return 1; } if (strcmpi(name, "imr") == 0) { imr = (int) value; return 1; } if (strcmpi(name, "greg") == 0) { greg = (int) value; return 1; } return 0; } void modify_register(void) { if (cc < 3) { __write("Usage: mr register_name value\n"); return; } if (!modify_known_register(cvals[1], get_int(2))) __write("Invalid register name. The valid registers are\n" "arp ov ovm intm dp arb cnf tc sxm c hm fsm xf fo txm pm pc t\n" "sp ar0 ar1 ar2 ar3 ar4 ar5 ar6 ar7 bio acc p\n" "drr dxr tim prd imr greg\n"); } void breakpoint(void) { if (cc < 2) { __write("Usage: bp addr\n"); return; } addr = (int) get_int(1); add_breakpoint(addr); } void go_n(long int r) { r = go_til_breakpoint(r); if (r == -1) { sprintf(toprint, "Breakpoint at %04X\n", pc); __write(toprint); } print_matching_symbols(pc); } void go(void) { if (cc < 2) go_n(-1); else go_n(get_int(1)); } void n_cycles(void) { if (cc < 2) { __write("Usage: cycles \n"); return; } stop_at = get_int(1); stop_at += cycles; while (cycles < stop_at) advance(); } void intrupt(void) { if (cc < 2) { __write("Usage: int type\n"); goto IntTypes; } if (strcmpi(cvals[1], "RS") == 0) { c25_interrupt(RS); return; } if (strcmpi(cvals[1], "INT0") == 0) { c25_interrupt(INT0); return; } if (strcmpi(cvals[1], "INT1") == 0) { c25_interrupt(INT1); return; } if (strcmpi(cvals[1], "INT2") == 0) { c25_interrupt(INT2); return; } if (strcmpi(cvals[1], "TINT") == 0) { c25_interrupt(TINT); return; } if (strcmpi(cvals[1], "RINT") == 0) { c25_interrupt(RINT); return; } if (strcmpi(cvals[1], "XINT") == 0) { c25_interrupt(XINT); return; } if (strcmpi(cvals[1], "TRAP") == 0) { c25_interrupt(TRAP); return; } __write("Invalid interrupt type!\n"); IntTypes: __write("Valid types: RS, INT0, INT1, INT2,\nTINT, RINT, XINT, TRAP\n"); } void find_matches(void) { sprintf(toprint, "Symbols matching current PC(%04X) are\n", pc); __write(toprint); if (print_matching_symbols(pc) == 0) __write("--none--\n"); } void toggle_bkgnd(void) { if (c25_background) __write("Stopping r"); else __write("R"); __write("unning C25 as a background process\n"); c25_background = !c25_background; } /* ======================================================================= */ /* Wait States */ /* ======================================================================= */ int progmem_waits(unsigned int a) { int i; for (i = 0; i < npw; i++) if (ui(pw[i][0]) <= ui(a) && ui(a) <= ui(pw[i][1])) return pw[i][2]; return 0; } int datamem_waits(unsigned int a) { int i; for (i = 0; i < ndw; i++) if (ui(dw[i][0]) <= ui(a) && ui(a) <= ui(dw[i][1])) return dw[i][2]; return 0; } void pm_wait_range(void) { if (cc < 4) { __write("Usage: pwait lo-addr hi-addr #wait-states\n"); return; } pw[npw][0] = (int) get_int(1); pw[npw][1] = (int) get_int(2); pw[npw][2] = (int) get_int(3); npw++; } void dm_wait_range(void) { if (cc < 4) { __write("Usage: dwait lo-addr hi-addr #wait-states\n"); return; } dw[ndw][0] = (int) get_int(1); dw[ndw][1] = (int) get_int(2); dw[ndw][2] = (int) get_int(3); ndw++; } /* ======================================================================= */ /* Text Searches in Screens */ /* ======================================================================= */ char search_string[40]; char *strstri(char *slong, char *sshort) { unsigned int i; char *L, *S; for (i = 0; i <= strlen(slong); i++) { L = &slong[i]; S = sshort; while (toupper(*S) == toupper(*L)) { S++; L++; if (*S == '\0') return &slong[i]; if (*L == '\0') return NULL; } } return NULL; } void find_next_occurence(char **head, int *first_line) { char *p, *q; int i, f_init; f_init = *first_line; for (i = 0, p = *head; i < *first_line; i++) { if (next_link(p) == NULL) return; p = next_link(p); } while ((q = next_link(p)) != NULL) { p = q; (*first_line)++; if (strstri(string_part(p), search_string) != NULL) return; } /* If no more occurences, don't change first_line */ *first_line = f_init; save_screen_buffer(listing); select_window(not_found_window); clear_n(not_found_window); __write_rc("Search string not found!", 1, 1); __write_rc("Press any key", 2, 1); __write_rc( "--------------------------------------------------------------", 3, 1); goto_xy(26, 1); if (getch() == 0) getch(); restore_screen_buffer(listing); select_window(listing_window); } void get_search_string(char **head, int *first_line) { save_screen_buffer(listing); select_window(search_string_window); clear_n(search_string_window); __write_rc( "--------------------------------------------------------------", 2, 1); __write_rc("Search string: ", 1, 1); gets(search_string); restore_screen_buffer(listing); select_window(listing_window); if (strstr(string_part(*head), search_string) == NULL) find_next_occurence(head, first_line); } /* ======================================================================= */ /* Help and Source Listing Screens */ /* ======================================================================= */ void get_file_line(void) { unsigned int i, j, j2; fgets(pre_line, 100, f); if (feof(f)) return; pre_line[strlen(pre_line) - 1] = '\0'; for (i = 0, j = 0; i < strlen(pre_line); i++) { if (pre_line[i] == '\t') { j2 = (j + 8) & 0xFFF8; while (j < j2) listline[j++] = ' '; } else listline[j++] = pre_line[i]; } listline[j] = '\0'; } void free_lines(char **first) { char *p, *q; /* if there is already stuff here, free() that all up */ p = *first; while (p != NULL) { q = next_link(p); free(p); p = q; } *first = NULL; } char *add_line(char **head, char *line) { char *p, *q; q = (char *) malloc(sizeof(char *) + strlen(line) + 1); if (q == NULL) return q; strcpy(string_part(q), line); set_next_link(q, NULL); if (*head == NULL) { *head = q; return q; } for (p = *head; next_link(p) != NULL; p = next_link(p)); set_next_link(p, q); return q; } void pull_in_file(char **head) { free_lines(head); f = fopen(cv[1], "r"); if (f == NULL) { sprintf(toprint, "Can't open file %s\n", cv[1]); __write(toprint); return; } *head = NULL; while (1) { get_file_line(); if (feof(f)) goto fini; if (add_line(head, listline) == NULL) { __write("File is too big for available memory.\n" "It has been truncated to fit.\n"); fini: fclose(f); return; } } } void pull_in_listing(void) { pull_in_file(&listing_head); } void redisplay_listing(char **head, int *first_line) { int i, j; char *p; clear_n(listing_window); end_file = 0; for (i = 0, p = *head; i < *first_line; i++) { if (next_link(p) == NULL) { end_file = 1; return; } p = next_link(p); } for (j = 1; i < *first_line + 25; i++, j++) { __write_rc(string_part(p), j, 1); if (next_link(p) == NULL) { end_file = 1; return; } p = next_link(p); } } void alternate_screen(char **head, int *first_line) { int i, prev_first = -1; char *p, *q; save_screen_buffer(regular); select_window(listing_window); while (1) { if (*first_line != prev_first) { redisplay_listing(head, first_line); prev_first = *first_line; } switch (getch()) { case '\0': switch (getch()) { case F5_key: get_search_string(head, first_line); break; case F6_key: find_next_occurence(head, first_line); break; case Page_Up_key: *first_line -= 24; break; case Page_Down_key: if (!end_file) *first_line += 24; break; case Home_key: *first_line = 0; break; case End_key: p = *head; *first_line = 0; while ((q = next_link(p)) != NULL) { p = q; (*first_line)++; } for (i = 0; i < 24 && *first_line > 0; i++, (*first_line)--); break; case Arrow_Down_key: if (!end_file) (*first_line)++; break; case Arrow_Up_key: (*first_line)--; break; default: goto fini; break; } if (*first_line < 0) *first_line = 0; break; default: fini: restore_screen_buffer(regular); select_window(regular_window); return; } } } void load_listing_file(char *word) { if (strchr(word, '.') == NULL) sprintf(cvals[1], "%s.lst", word); else strcpy(cvals[1], word); cv[1] = cvals[1]; f = fopen(cv[1], "r"); pull_in_file(&listing_head); } void load_help_file(void) { strcpy(cvals[1], "c25sim.hlp"); cv[1] = cvals[1]; f = fopen(cv[1], "r"); pull_in_file(&help_head); } /* ======================================================================= */ /* Symbol Table */ /* ======================================================================= */ void load_map_file(char *word) { int i, addr, dummy1; FILE *f; for (i = 0; i < (int) strlen(word); i++) word[i] = toupper(word[i]); if (strchr(word, '.') == NULL) sprintf(name, "%s.map", word); else strcpy(name, word); f = fopen(name, "r"); if (f == NULL) { sprintf(toprint, "No map file available\n"); __write(toprint); return; } while (1) { fgets(fline, 80, f); if (strcmp(fline, "GLOBAL SYMBOLS\n") == 0) break; if (feof(f)) { fclose(f); return; } } fgets(fline, 80, f); fgets(fline, 80, f); fgets(fline, 80, f); free_lines(&first_symbol); first_symbol = NULL; while (1) { fgets(fline, 80, f); if (sscanf(fline, "%x %s %x %s", &addr, name, &dummy1, dummy2) < 4) goto fini; sprintf(fline, "%s %04X", name, addr); if (add_line(&first_symbol, fline) == NULL) { __write("Out of room for labels and global variables!\n"); goto fini; } } fini: fclose(f); return; } int lookup_symbol(char *name) { int n; char *p, q[40]; for (p = first_symbol; p != NULL; p = next_link(p)) { sscanf(string_part(p), "%s %x", q, &n); if (strcmpi(q, name) == 0) return n; } sprintf(toprint, "Couldn't find symbol \"%s\"\n", name); __write(toprint); return 0; } int print_matching_symbols(int a) { char *p, q[40]; int x, n = 0; for (p = first_symbol; p != NULL; p = next_link(p)) { sscanf(string_part(p), "%s %x", q, &x); if (x == a) { sprintf(toprint, "%s\n", q); __write(toprint); n++; } } return n; } int print_all_symbols(void) { char *p; int n = 0; for (p = first_symbol; p != NULL; p = next_link(p)) { sprintf(toprint, "%s\n", string_part(p)); __write(toprint); n++; } return n; } /* ======================================================================= */ /* Main */ /* ======================================================================= */ static void print_binary(char *name, int x, int n) { int mask = 1 << (n - 1); __write(name); __write(":"); while (mask) { if (x & mask) __write("1"); else __write("0"); mask >>= 1; } sprintf(toprint, "(%d) ", x); __write(toprint); } static void print_bit(char *name, int x) { __write(name); __write(":"); if (x) __write("1 "); else __write("0 "); } void make_report(void) { int i; select_window(register_window); sprintf(toprint, "PC: %04X\n", pc); __write_rc(toprint, 1, 1); sprintf(toprint, "Steps: %ld \n", steps_taken); __write(toprint); sprintf(toprint, "Cycles: %ld \n", cycles); __write(toprint); i = read_program_memory(pc); sprintf(toprint, "Opcode: %04X ", i); __write(toprint); sprintf(toprint, "%s \n", disassemble(i)); __write(toprint); sprintf(toprint, "ACC: %08lX ", accumulator); __write(toprint); print_binary("ARP", arp, 3); __write("\n"); __write("ARs: "); for (i = 0; i < 8; i++) { sprintf(toprint, "%04X ", ar[i]); __write(toprint); if ((i % 3) == 2) __write("\n "); } __write("\n"); __write("Stack: "); for (i = 0; i < 8; i++) { if (i < _sp) sprintf(toprint, "%04X ", _stack[(_sp - 1) - i]); else strcpy(toprint, "---- "); __write(toprint); if ((i % 3) == 2) __write("\n "); } __write("\n"); print_binary("DP", dp, 9); print_binary("ARB", arb, 3); __write("\n"); print_binary("PM", pm, 2); print_bit("OV", ov); print_bit("OVM", ovm); print_bit("INTM", intm); __write("\n"); print_bit("CNF", cnf); print_bit("TC", tc); print_bit("SXM", sxm); print_bit("C", c); print_bit("HM", hm); __write("\n"); print_bit("FSM", fsm); print_bit("XF", xf); print_bit("FO", fo); print_bit("TXM", txm); __write("\n"); sprintf(toprint, "T: %04X\n", t_register); __write(toprint); sprintf(toprint, "P: %08lX\n", p_register); __write(toprint); sprintf(toprint, "DRR: %04X\n", drr); __write(toprint); sprintf(toprint, "DXR: %04X\n", dxr); __write(toprint); sprintf(toprint, "TIM: %04X\n", tim); __write(toprint); sprintf(toprint, "PRD: %04X\n", prd); __write(toprint); sprintf(toprint, "IMR: %04X\n", imr); __write(toprint); sprintf(toprint, "GREG: %04X\n", greg); __write(toprint); select_window(regular_window); } void main(int argc, char *argv[]) { int c; regular_window = create_window(1, DIVISION, 1, 25); register_window = create_window(DIVISION + 1, 80, 1, 25); listing_window = create_window(1, 80, 1, 25); search_string_window = create_window(1, 80, 1, 2); not_found_window = create_window(1, 80, 1, 3); select_window(regular_window); /* If a file was specified on the command line, get it now */ if (argc > 1) { load_hex_files(argv[1]); load_map_file(argv[1]); load_listing_file(argv[1]); } /* First set up the simulator */ initialize_simulator(); load_help_file(); make_report(); /* set up wait state functions for program and data memory */ pwaitf = progmem_waits; dwaitf = datamem_waits; __write("Press F1 for help.\n"); __write("READY> "); while (1) { if (c25_background) advance(); if (kbhit()) { c = getch(); switch (c) { case '\0': c = getch(); switch (c) { case F1_key: alternate_screen(&help_head, &help_first_line); break; case F2_key: alternate_screen( &listing_head, &listing_first_line); break; case F3_key: alternate_screen( &first_symbol, &symbol_table_first_line); case F4_key: advance(); make_report(); break; default: break; } break; case '\r': __write("\n"); do_menu(); make_report(); for (c = 0; c < 80; c++) line[c] = '\0'; __write("READY> "); break; case '\b': if (strlen(line) == 0) break; line[strlen(line) - 1] = '\0'; delete_char(); break; case 27: /* Escape */ while (strlen(line) > 0) { line[strlen(line) - 1] = '\0'; delete_char(); } break; default: sprintf(toprint, "%c", c); __write(toprint); line[strlen(line)] = (char) c; break; } } } }