/******************************************************************************* * This file contains the TASCOM ECB driver functions. * * * Project: TASCOM * File name: ecbdriv_els.c * * Author: J. Bundgaard Nov. 1991. * * * * Copyright (C) Risoe National Laboratory, 1991-1994, All rights reserved *******************************************************************************/ /******************************************************************************* *& modified by: *& *& *& V003.101 P.S. 26-APR-2004 *& For the ecb_load program only. *& *& *&*****************************************************************************/ #include #include #include "ecb_load.h" #include GPIB_H /******************************************************************************* * Static variables *******************************************************************************/ static repete = 1; static int look_up[] = {10, 11, 12, 13, 14 ,15}; /******************************************************************************* * External variables defined in this file. *******************************************************************************/ int x_ecb1 = -1; /* Unit descriptor of ECB system #1 */ Z80_reg x_inreg; /* Z80 registers b,c,d and e before call */ Z80_reg x_outreg; /* Z80 registers b,c,d and e after call */ unsigned char x_ecb_data[ECB_BYTES]; /* Array to hold data blocks for ECB */ int x_ecb_error_count = 0; /* Counter for ECB call errors */ int x_cpu_typ = 0; /* =0: WP-CPU, =1: P2701, =2: P2701 + P2501 */ Ecb_data x_ecba; /* DMA data from P2701a ECB-CPU */ /******************************************************************************* * Prototypes for functions defined in this file. *******************************************************************************/ extern void Ecb_init(void); extern int Ecb_error(void); extern void Ecb_unit (void); /* Establish unit No. for ECB */ extern int Ecb_func (int , unsigned char); /* Call ECB function */ extern void Ecb_read (int, unsigned short, unsigned short); /* Read n bytes */ extern void Ecb_write (int, unsigned short, unsigned short); /* Write n bytes */ static int Ecb_prepare (int, unsigned char, unsigned short, unsigned short); static int Ecb_send_func (int, unsigned char); /* Send function code */ static void Ecb_error_func (char *, unsigned char, int); static void Restart_ecb_func (int unit, unsigned char function); static int Restart_ecb_prepare(int,unsigned char,unsigned short,unsigned short); static void Do_reset (void); extern void Ecb_down_load (FILE *stream); static unsigned long Hex_to_bin(char c); static char Bin_to_hex (int i); extern int Ecb_type (int); /******************************************************************************* * ECB system initialisation *******************************************************************************/ extern void Ecb_init(void) { x_cpu_typ = 1; /* New CPU module, P2701 */ x_ecb1 = -1; if (x_gpib0 >= 0) { x_ecb1 = ibfind (ECB1); /* Now see if the ECB system is avaiable */ if (x_ecb1 <= 0) { x_ecb1 = -1; x_error_text =(char *) ECB1; x_tas_error = GPIB_FIND_ERROR; Ecb_load_error(); } else { ibsic (x_gpib0); /* Send interface clear */ usleep (300000); /* Wait 0.3 sec. */ ibtmo (x_ecb1, T10s); /* Time out 10 sec. */ } } x_tas_error = FALSE; return; } /******************************************************************************* * Function to call a Z80 function (subroutine) without interrupt. * This means that the function No. must be greater than or equal to * 128 (function 0) and less than or equal to 191 (function 63). * 'Unit' is the address of the ECB system on the GPIB bus. Four Z80 regs. * are transferred upon the call from the host to the ECB system, and * again read back to the host upon exit from the ECB function. This * mechanismen is used to tranfer of arguments and results. Two global * structures are used for the purpose, x_inreg and x_outreg. *******************************************************************************/ extern int Ecb_func (int unit, unsigned char function) { int byte_cnt; short status; char *ecb_error_text; void TC_FAR *point_input = &x_inreg; void TC_FAR *point_output = &x_outreg; if (Ecb_send_func (unit, function) == FALSE) { if (repete == 1) Restart_ecb_func (unit, function); /* GPIB error: recall Ecb_func() once */ return (FALSE); } /* Function accepted. Send the 4 Z80 register values */ byte_cnt = 4; status = ibwrt (unit, point_input, byte_cnt); if (status < 0) { if (repete ==1) { Restart_ecb_func (unit, function); /* GPIB error: recall Ecb_func() once */ return; } if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_WRITE_ERROR; ecb_error_text = "during write of data bytes at ECB function"; Ecb_error_func(ecb_error_text, function, unit); return(FALSE); } /* Wait for the function to complete and then receive the 4 Z80 regs. values */ status = ibrd (unit, point_output, byte_cnt); if (status < 0) { if (repete ==1) { Restart_ecb_func (unit, function); /* GPIB error: recall Ecb_func() once */ return(FALSE); } if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_READ_ERROR; ecb_error_text = "during read of data bytes at ECB function"; Ecb_error_func(ecb_error_text, function, unit); return(FALSE); } return(TRUE); } /******************************************************************************* * Function to re-call Ecb_func() in case of a GPIB bus error. *******************************************************************************/ static void Restart_ecb_func (int unit, unsigned char function) { Do_reset(); Ecb_func (unit, function); repete = 1; /* Reset repete to allow re-calls */ return; } /******************************************************************************* * Function to re-call Ecb_send_func() in case of a GPIB bus error. *******************************************************************************/ static int Restart_ecb_prepare (int unit, unsigned char function, unsigned short address, unsigned short byte_count) { short status; Do_reset(); status = Ecb_prepare (unit, function, address, byte_count); repete = 1; /* Reset repete to allow re-calls */ return(status); } /******************************************************************************* * Send Interface clear and print a message. *******************************************************************************/ static void Do_reset (void) { ibsic (x_gpib0); /* Send interface clear */ usleep (300000); /* Wait 0.3 sec. */ ibsic (x_gpib0); /* Send interface clear */ usleep (300000); /* Wait 0.3 sec. */ repete = 0; /* No more re-calls */ return; } /******************************************************************************* * Function that transfers 'byte_count' bytes from the ECB system to * the host. 'Address' specifies source start address in the Z80 me- * mory space. Destination is the global unsigned character array * x_ecb_data. *******************************************************************************/ extern void Ecb_read (int unit, unsigned short address, unsigned short byte_count) { short status; void TC_FAR *point_data = &x_ecb_data; if (Ecb_prepare (unit, READ_N_BYTES, address, byte_count) == FALSE) return; /* Read the requested No. of bytes */ status = ibrd (unit, point_data, (int) byte_count); if (status < 0) { if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_READ_ERROR; return; } return; } /******************************************************************************* * Function that transfers 'byte_count' bytes from the host to the ECB * system. 'Address' specifies destination start address in the Z80 me- * mory space. Source is the global unsigned character array x_ecb_data. *******************************************************************************/ extern void Ecb_write (int unit, unsigned short address, unsigned short byte_count) { short status; char *ecb_error_text; void TC_FAR *point_data = &x_ecb_data; if (Ecb_prepare (unit, WRITE_N_BYTES, address, byte_count) == FALSE) return; /* Write the requested No. of bytes */ status = ibwrt (unit, point_data, (int) byte_count); if (status < 0) { if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_WRITE_ERROR; ecb_error_text = ""; Ecb_error_func(ecb_error_text, 0, unit); return; } /* Receive a dummy byte */ byte_count = 1; status = ibrd (unit, point_data, (int) byte_count); if (status < 0) { if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_READ_ERROR; return; } return; } /******************************************************************************* * Prepare an ECB read or write n bytes. See Ecb_read() and Ecb_write(). *******************************************************************************/ static int Ecb_prepare (int unit, unsigned char function, unsigned short address, unsigned short byte_count) { int byte_cnt; short status; Swap save, adr, count; char *ecb_error_text; void TC_FAR *point_adress = (Swap *) &adr.word; void TC_FAR *point_count = (Swap *) &count.word; if (byte_count > ECB_BYTES) { x_error_int = byte_count; x_tas_error = ECB_OVERFLOW; ecb_error_text = ""; Ecb_error_func(ecb_error_text, 0, unit); return (FALSE); } save.word = address; /* Swap address bytes */ adr.b.lsb = save.b.msb; adr.b.msb = save.b.lsb; save.word = byte_count; /* Swap byte count bytes */ count.b.lsb = save.b.msb; count.b.msb = save.b.lsb; if (Ecb_send_func (unit, function) == FALSE) { if (repete ==1) { /* GPIB error, Restart Ecb_prepare() once */ status = Restart_ecb_prepare (unit, function, address, byte_count); return(status); } ecb_error_text = "during write of ECB function code "; Ecb_error_func(ecb_error_text, function, unit); return (FALSE); } byte_cnt = 2; /* Function accepted, send the two byte address value */ status = ibwrt (unit, point_adress, byte_cnt); if (status < 0) { if (repete ==1) { /* GPIB error, Restart Ecb_prepare() once */ Restart_ecb_prepare (unit, function, address, byte_count); return(status); } if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_WRITE_ERROR; ecb_error_text = ""; Ecb_error_func(ecb_error_text, 0, unit); return (FALSE); } /* Send the two byte byte_count value */ status = ibwrt (unit, point_count, byte_cnt); if (status < 0) { if (repete ==1) { /* GPIB error, Restart Ecb_prepare() once */ Restart_ecb_prepare (unit, function, address, byte_count); return(status); } if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_WRITE_ERROR; ecb_error_text = ""; Ecb_error_func(ecb_error_text, 0, unit); return (FALSE); } return (TRUE); } /******************************************************************************* * Function to send ECB function code and receive an acknowledge * character as response. *******************************************************************************/ static int Ecb_send_func (int unit, unsigned char function) { unsigned char response; unsigned long byte_cnt; int error_type; short status; char *ecb_error_text; void TC_FAR *point_func = &function; void TC_FAR *point_resp = &response; byte_cnt = 1; /* Send function code */ status = ibwrt (unit, point_func, byte_cnt); error_type = iberr; if (status < 0) { if (repete == 1) return(FALSE); if (status | TIMO) { if ((error_type == ENOL) || (error_type == EBUS)) { x_error_text = ECBTEXT; x_tas_error = GPIB_NO_LISNER_ERROR; Ecb_load_error(); return (FALSE); } x_error_text = "Timeout"; } else x_error_text = '\0'; x_tas_error = GPIB_WRITE_ERROR; Ecb_load_error(); return (FALSE); } /* Get acknowledge byte back */ status = ibrd (unit, point_resp, byte_cnt); if (status < 0) { if (repete == 1) return(FALSE); if (status | TIMO) x_error_text = "Timeout"; else x_error_text = '\0'; x_tas_error = GPIB_READ_ERROR; ecb_error_text = "during read of ack-byte at ECB function "; Ecb_error_func(ecb_error_text, function, unit); return (FALSE); } if (response != ACKN) /* Acknowledge ? */ { x_error_int = function; x_tas_error = ECB_ILLEGAL_FUNC; ecb_error_text = " ECB function code "; Ecb_error_func(ecb_error_text, function, unit); return (FALSE); } return (TRUE); } /******************************************************************************* * Errors at calls to the ECB system. After two ECB errors TASCOM * returns to DOS. *******************************************************************************/ static void Ecb_error_func (char *ecb_error_text, unsigned char function, int unit) { Ecb_load_error(); if (function != 0) { printf ("%s %d\n",ecb_error_text, function); fflush (stdout); exit(0); } return; } /******************************************************************************* * Errors at calls to the ECB system. After two ECB errors TASCOM * returns to DOS. *******************************************************************************/ static void Ecb_error_func1 (char *ecb_error_text, unsigned char function, int unit) { Ecb_load_error(); if (function != 0) { printf ("%s %d\n",ecb_error_text, function); fflush (stdout); exit(0); } return; } /****************************************************************************** * Down load the ECB program. * Reads lines from the HEX file and add up to 20 data lines together before * sending them to the ECB system. ******************************************************************************/ extern void Ecb_down_load (FILE *stream) { int ecb_type, unit, function, load_count = -1; char *point; unsigned short byte_count, address; char line[F_BUFSIZ]; unsigned long type, no_bytes, adrs, total_bytes, old_adrs, total1, total0, total2; int line_no = 0; void TC_FAR *point_func = &function; int line_not_output = 0; /* if =1: data waiting in line[] */ void TC_FAR *line9 = &line[9]; /* Stop_display(); */ for (;;) { if (line_not_output == 1) line_not_output = 0; /* Start with old line */ else { /* Read a line from file */ point = fgets (line, F_BUFSIZ, stream); if (point != NULL) { byte_count = strlen(line); byte_count -= 4; /* Remove checksum and \n in the */ line[byte_count+1] = NUL; /* line, i.e. the four last characters */ line[0] = '0'; /* Replace : in line[0] with 0 */ } else { if (!ferror(stream)) byte_count = 0; else { fclose (stream); stream = NULL; x_tas_error = FILE_READ; Ecb_load_error (); printf (" during download of the ECB program\n"); /* Start_display(); */ return; } } } line_no += 1; if (byte_count != 0) { if (line_no == 1) strcpy (x_ecb_data, line); type = (Hex_to_bin(line[7]) << 4) + Hex_to_bin(line[8]); if (type != 0) { if (line_no > 1) /* Output buffer and mark that */ line_not_output = 1; /* last input line has not been output */ } else { no_bytes = (Hex_to_bin(line[1]) << 4) + Hex_to_bin(line[2]); adrs = (Hex_to_bin(line[3]) << 12) + (Hex_to_bin(line[4]) << 8) + (Hex_to_bin(line[5]) << 4) + Hex_to_bin(line[6]); if (line_no == 1) { total_bytes = no_bytes; old_adrs = adrs; continue; /* Get next input line */ } else { if (old_adrs + no_bytes == adrs) { /* Contigious addresses */ total_bytes += no_bytes; old_adrs = adrs; strcat (x_ecb_data, line9); /* Add the new bytes to buffer */ total0 = total_bytes/256; /* and adjust number of bytes */ x_ecb_data[0] = Bin_to_hex(total0); total1 = total_bytes - 256*total0; total2 = total1/16; x_ecb_data[1] = Bin_to_hex(total2); x_ecb_data[2] = Bin_to_hex(total1 - 16*total2); if (line_no < 20) /* Max 20 lines together */ continue; /* Get next input line */ } } line_not_output = 0; /* Output buffer, nothing waiting in line[] */ } unit = x_ecb1; address = 1; byte_count = strlen (x_ecb_data); Ecb_write (unit, address, byte_count); /* Write a line to ECB */ line_no = 0; /* if (Test_ctrl_c()) /* { /* Start_display(); /* return; /* Control(c) hit */ /* } */ if (load_count == -1) /* Type Loading followed by dots while */ { /* down loading the file */ printf ("\nLoading"); fflush (stdout); load_count = 0; } load_count += 1; if (load_count > 15) { printf ("."); fflush (stdout); load_count = 0; } function = ECB_DOWN_LOAD; Ecb_func (unit, function); /* Call ECB download function */ if (x_outreg.b != LOAD_NEXT) /* Wait for reply from ECB */ break; /* If LOAD_NEXT, get next line, else finished */ } } printf ("\nLoading complete\n"); fflush (stdout); /* Start_display(); */ return; } /******************************************************************************* * Convert HEX to bin *******************************************************************************/ static unsigned long Hex_to_bin(char c) { if(isdigit((int) c)) return (c - '0'); else return look_up[c - 'A']; } /******************************************************************************* * Convert Bin to HEX *******************************************************************************/ static char Bin_to_hex (int i) { if(i <= 9) return ( (char)(i + (int)('0')) ); else return ( (char)( (i - 10) + (int)('A')) ); } /****************************************************************************** * Get type and version of the ECB program. If return_value is TYPE_OUT, the * type is returned as 1 for RAM and 0 for ROM. If return_value is VERS_OUT, * the version number * 100 is returned. * If return_value = 0, type and version are printed. ******************************************************************************/ extern int Ecb_type (int return_value) { int unit, function; int version, status; /* P2701a CPU: Get ROM/RAM type */ unit = x_ecb1; function = ECB_TYPE; status = Ecb_func (unit, function); if (status == 0) exit(0); version = 100*(int)x_outreg.b + 10*(int)x_outreg.c + (int)x_outreg.e; if (return_value == TYPE_OUT) return((int) x_outreg.d); if (return_value == VERS_OUT) return(version); printf ("ECB program: "); if (x_outreg.d == 1) printf ("RAM"); else if (x_outreg.d == 0) printf ("ROM"); printf (" mode, version %4.2f\n", ((float) version)/100); fflush (stdout); return((int) x_outreg.d); } /******************************************************************************* * Ecb option error routine. *******************************************************************************/ extern int Ecb_error(void) { switch (x_tas_error) { case ECB_OVERFLOW: printf (" Byte count %d overflows ECB data buffer.", x_error_int); break; case ECB_ILLEGAL_FUNC: printf (" No such ECB function: %d", x_error_int); break; default: return(NOT_FOUND); } printf ("\n"); fflush (stdout); return(FOUND); }