! File: ST2HEX2.FOR ! Date: 2-5-1994 ! Version: 2.1 ! Author: C. S. Tritt ! ! Copyright 1993 and 1994 by Charles S. Tritt, Milwaukee, WI ! ! This program may be freely copied and modified as long as the original and ! subsequent authors are acknowledged. It may not be used for commercial ! purposes without the author's permission. This program is not guaranteed to ! function as described. The user assumes all risks and liabilities related ! to its use. ! ! ! I N S T R U C T I O N S ! ! This program translates an ASCII file containing state table data into an ! ASCII file containing two digit hexadecimal (hex) numbers. This hex file ! can be used to program an EPROM that can be used with D flip-flops to ! implement the machine described in the state table. This program can ! handle don't care conditions and provides for default transitions. It can ! handle designs involving between 4 and 14 address lines and 8 output lines ! (up to 16 K x 8 bit EPROM's) ! ! The state table file must have an eight letter name and must have a .STF ! extension. The hex file will have the same name as the state table file ! but will have a .HEX extension. ! ! The format of the state table file is: ! ! Comment line 1 ! Comment line 2 ! Num_Addr_Bits Default_Output ! Condition_1 Output_1 Comments... ! Condition_2 Output_2 ! : : ! Condition_n Output_n ! ! where the Comment lines identify the design but are not otherwise used, ! Num_Addr_Bits is the number of EPROM address lines used in the design ! (number of inputs plus number of flip-flops), Default_Output is the ! default EPROM data value, Condition_x's are the present state & inputs ! columns from the state table and Output_x's are the next state & outputs ! columns from the state table. ! ! Values other than Num_Addr_Bits are represented in binary with the MSB's on ! the left. Num_Addr_Bits should be in decimal. Comments may follow the last ! bit in the Output_x value. ! ! The format and range of the data values is important. Num_Addr_Lines must ! be a 2 digit decimal number between 4 and 14 (inclusive). Default_Output ! must be an 8 digit binary number. The Condition_x values must be ! Num_Addr_Lines digit values containing only 0's, 1's and X's. There must ! be exactly one space between the conditions and outputs columns. The ! Output_x values must be 8 digit binary values. ! ! E X A M P L E ! ! The state diagram below describes a presetable BCD up-down counter. It ! has two inputs (Enable and Down/Up') and two outputs (Roll over and Roll ! under). When Enable is low, the machine goes to or stays in state 5. ! When Enable is high and Down/Up' is low, it counts up. When Enable and ! Down/Up' are both high, it counts down. Roll over is made high when the ! count goes from 9 to 0. Roll under is made high when the count goes from ! 0 to 9. If the machine gets in an unused state and Enable is high, it ! goes to state 0 and raises both Roll over and Roll under indicating an ! error has occurred. ! ! +-------------+ ! | Any unused | ! | state | ! +-------------+ ! | ! | 1X/11 ! v ! +-------+ 10/10 +-------+ ! | |---------->| | ! | 1001 | 11/01 | 0000 | ! | |<----------| | ! +-------+ +-------+ ! ^ | ^ | ! 10/00 | | 11/00 11/00 | | 10/00 ! | v | v ! +-------+ +-------+ ! | 1000 | | 0001 | ! +-------+ +-------+ ! ^ | ^ | ! 10/00 | | 11/00 11/00 | | 10/00 ! | v | v ! +-------+ +-------+ ! | 0111 | | 0010 | ! +-------+ +-------+ ! ^ | ^ | ! 10/00 | | 11/00 11/00 | | 10/00 ! | v | v ! +-------+ +-------+ ! | 0110 | | 0011 | ! +-------+ +-------+ ! ^ | ^ | ! 10/00 | | 11/00 11/00 | | 10/00 ! | v | v ! +-------+ 10/00 +-------+ ! | |---------->| | ! | 0101 | 11/00 | 0100 | ! | |<----------| | ! +-------+ +-------+ ! ^ ! 0X/00 | ! | ! +-------+ ! | Any | ! | State | ! +-------+ ! ! The state table input file for this machine would be: ! ! File: UDBCDPS5.STF Machine: Up/down BCD counter with preset to 5 ! Version 4.0 / 2-5-94 / By C. S. Tritt ! 6 0011000 Indicate error with 11 default output ! 0XXXXX 00000101 Go to state five when preset is low ! 100000 00000001 Count up from 0 ! 110000 00011001 Count down from 0, indicate roll under ! 100001 00000010 Count up from 1 ! 110001 00000000 Count down from 1 ! 100010 00000011 Count up from 2 ! 110010 00000001 Count down from 2 ! 100011 00000100 Count up from 3 ! 110011 00000010 Count down from 3 ! 100100 00000101 Count up from 4 ! 110100 00000011 Count down from 4 ! 100101 00000110 Count up from 5 ! 110101 00000100 Count down from 5 ! 100110 00000111 Count up from 6 ! 110110 00000101 Count down from 6 ! 100111 00001000 Count up from 7 ! 110111 00000110 Count down from 7 ! 101000 00001001 Count up from 8 ! 111000 00000111 Count down from 8 ! 101001 00100000 Count up from 9, indicate roll over ! 111001 00001000 Count down from 9 ! ! In this example, the two most significant bits of the output byte are not ! used. The next bit indicates that the counter has rolled over while counting ! upwards. The following bit indicates that the counter has rolled under while ! counting downwards. The remaining four bits are the next states for the ! flip-flops. ! ! The most significant condition (EPROM input) bit is an active low synchronous ! preset to 5 input. This input must be 1 for the counter to count. The next ! bit indicates count direction (0 meaning up, 1 meaning down). The remaining ! four bits are the present state inputs from the flip-flops. ! ! If the counter gets into an unused state it will, by default, output 11 and ! go to state of 0000 on the next clock transition. ! ! This example shows how X's are used to indicate don't care conditions. ! Whenever the preset input is low, the counter will go to state 0101 (5) on ! the next clock transition regardless of the states of the other inputs. It ! will stay in this state as long as the preset input is held low. ! ! This example also shows that not all possible conditions have to be listed ! in the state table. Unlisted conditions (memory locations) will be filled ! with the Default_Output value. ! ! The circuit implementing this design would be: ! ! MSB ! +---------+ ! +-----------| A F-F D |<----------+ ! | +---------+ | ! | | ! | +---------+ | ! | +---------| B F-F D |<--------+ | ! | | +---------+ | | ! | | | | ! | | +---------+ | | ! | | +-------| C F-F D |<------+ | | ! | | | +---------+ | | | ! | | | | | | ! | | | +---------+ | | | ! | | | +-----| D F-F D |<----+ | | | ! | | | | +---------+ | | | | ! | | | | LSB | | | | ! | | | | | | | | ! | | | | +---------+ | | | | ! | | | | | EPROM | | | | | ! | | | | | | | | | | ! | | | +---->| I0 O0 |-----+ | | | ! | | +------>| I1 O1 |-------+ | | ! | +-------->| I2 O2 |---------+ | ! +---------->| I3 O3 |-----------+ ! Down/Up' --->| I4 O4 |---> Roll under ! Enable ----->| I5 O5 |---> Roll over ! | . O6 | ! | : O7 | ! | | ! +---------+ ! ! All unused inputs should be tied low and all unused outputs should be left ! open. Note the inherent "Mealyness" of the machine. The ROM outputs may ! contain gliches. ! ! P R O G R A M D O C U M E N T A T I O N ! ! This program was written for MS FORTRAN version 5.1 and MS-DOS 5.0. It ! should require only minor modifications to work with most other modern ! Fortran compilers and operating systems. Search this file for the word ! "standard" to locate the use of non-standard Fortran features. ! ! Outputs from the state table are initially held in a 2 element array of ! character*4's, BOUT. Each of these strings hold 1 nibble of the output byte. ! Valid values are 0000 through 1111. The nibbles are numbered 1 and 2. ! Binary output values are converted to hex and stored in the character*2 ! variable HOUT. Valid character values are 0 throught F. ! ! Conditions from the state table are held in the CNDTN array. CNDTN is a 14 ! element array of characters. Each element represents 1 bit of the condition. ! Valid values are 0, 1, and X. X's represent don't care conditions. The bits ! are numbered from 1 (LSB) to 14 (MSB). The MSB is on the left. ! ! MHEXA an array of character*2 strings. MHEXA elements specify data stored at ! the corresponding EPROM addresses. Valid character values are 0 throught F. ! The MHEXA elements are numbered from 0 to 16383. ! ! Binary values are assumed to be written with the MSB to the left. Fortran ! numbers characters in strings from left to right so the MSN's of HDFLT, ! MHEXA, HOUT are 1's and the LSN's are 2's. Therefore, the MSN's of BDFLT ! and BOUT were made the first elements and the LSN's were made the second ! elements. ! ! The logical variable ERROR and integer variable ERRNUM are used in a global ! error handling scheme. ERROR is set to .TRUE. and ERRNUM is set to a ! particular value when a non-recoverable error occurs. Most code is bypassed ! when ERROR true. The value of ERRNUM is used to display an explaination ! of the problem near the end of the program. The logical variable DONE is ! set to .TRUE. when the end of the data file is reached. ! ! Pseudocode: ! ! Get file names (FNAMES) from the user ! Open the input file (unit 10) ! Read comments, display and discard them ! Read NADDRSS and BDFLT ! Translate BDFLT to HDFLT ! Fill MHEXA array with HDFLT values ! Read the first line from the state table file (CNDTN & BOUT) ! While not done and there are no errors... ! Translate BOUT to HOUT ! Search for addresses matching the condition and insert HOUT into the ! corresponding MHEXA location when there is a match ! Read the next line from the state table file ! End While ! Close the input file ! Open the output file (unit 11) ! Write MHEXA to the output file (16 values/line) ! Close the output file ! Display error or done text ! ! Variables ! ! CMMNT char*68 Comments from beginning of state table file ! FNAMES char*8 Root file names (not including .HEX or .STF) ! FSIN char*12 Full input file specification (includes .STF) ! FSOUT char*12 Full output file specification (includes .HEX) ! OLDOUT logic Flag indicating that the output file already exists ! REPLACE char*1 Character indicating if old output file should be replaced ! DONE logic Flag indicating the end of the data file has been reached ! ERROR logic Flag indicating that an error occured ! ERRNUM int The number of the error that occured ! LINE int Line number in input (.STF) file being read ! IOSTAT int I/O status number (nonzero indicates an error) ! INUNIT int Input unit number ! OUTUNIT int Output unit number ! NADDRSS int Number of address bits used in the design ! LASTELMT int Number of last element used in MHEXA array (2^MADDRSS-1) ! INFRMT char*16 Input format string ! BDFLT char*4 Default output nibbles in binary form (2 element array) ! HDFLT char*2 Two letter hex code for default output ! MHEXA char*2 Master hex output array (16,384 element array) ! MATCH logic Flag indicating address and conditions match ! CNDTN char*1 Condition from state table (14 element array) ! BOUT char*4 Output value in binary form (2 element array) ! HOUT char*2 Output value in two character hex form ! I int Loop counter used for bits and nibbles ! J int Loop counter used for addresses ! K int Loop counter used for addresses ! ! Functions ! ! ADDRSBIT char*1 Takes two parameters. The first, ADDR, is an integer and ! is the address to check. The second, BIT, is also an ! integer and is the the bit within the address to return. ! The value returned (1 or 0) is the value of the specified ! bit within the specified address. Bits are numbered ! starting from 1 for the least significant bit. ! ! BI2HEX char*1 Takes one parameter. This parameter, BNRY, is a character ! string containing a 4 bit binary number in decimal form. ! The value returned is the 1 character representation (from ! 0 to G) of the binary value passed to the function. The ! return of a 'G' indicates an invalid BNRY value was passed ! to the function. ! program ST2HEX2 ! ! Turn off default variable typing. This is not standard FORTRAN. ! implicit none ! ! Declare variables ! integer INUNIT, OUTUNIT, NADDRSS, LASTELMT, I, J, K integer ERRNUM, IOSTAT, LINE logical ERROR, MATCH, OLDOUT, DONE character*68 CMMNT character*16 INFRMT character*12 FSIN, FSOUT character*8 FNAMES character*4 BDFLT(2), BOUT(2) character*2 HDFLT, HOUT, MHEXA(0:16383) character*1 CNDTN(14), BI2HEX, ADDRSBIT, REPLACE ! ! Specify parameters for I/O units ! parameter(INUNIT = 10, OUTUNIT = 11) ! ! Initialize error scheme variables ! data ERROR, ERRNUM, DONE / .FALSE., 0, .FALSE. / ! ! Prompt for and read root file name. Build file specifications. ! write(*,500) read(*,510) FNAMES FSIN = FNAMES // '.STF' FSOUT = FNAMES // '.HEX' ! ! Open input file, read and display comments. ! open(unit=INUNIT, file=FSIN, status='OLD', IOSTAT=IOSTAT) if (IOSTAT.ne.0) then ERROR = .TRUE. ERRNUM = 1 end if ! if (.not.ERROR) then read(INUNIT,520) CMMNT write(*,*) write(*,530) ' Processing: ',CMMNT read(INUNIT,520) CMMNT write(*,530) ' ',CMMNT end if ! ! Read and verify number of address bits value. Read, convert and ! verify default output value. Echo the values read. ! if (.not.ERROR) then read(INUNIT, 540, IOSTAT=IOSTAT) NADDRSS, BDFLT(1), BDFLT(2) if (IOSTAT.ne.0) then ERROR = .TRUE. ERRNUM = 2 end if end if ! if (.not.ERROR) then if ((NADDRSS.lt.4).or.(NADDRSS.gt.14)) then ERROR = .TRUE. ERRNUM = 3 else HDFLT(1:1) = BI2HEX(BDFLT(1)) HDFLT(2:2) = BI2HEX(BDFLT(2)) if ((HDFLT(1:1).eq.'G').or.(HDFLT(2:2).eq.'G')) then ERROR = .TRUE. ERRNUM = 4 else write(*, 550) HDFLT, NADDRSS LASTELMT = 2 ** NADDRSS - 1 end if end if end if ! ! Load output array with default values. This unlabeled do loop is not ! standard Fortran. ! if (.not.ERROR) then do J = 0, LASTELMT MHEXA(J) = HDFLT end do end if ! ! Start counting lines, create input format, read first condition/output ! line from state table. ! if (.not.ERROR) then LINE = 4 write(INFRMT, 560) NADDRSS read(INUNIT, INFRMT, IOSTAT=IOSTAT) & (CNDTN(I), I = NADDRSS,1,-1), & (BOUT(I), I = 1,2) if (IOSTAT.ne.0) then ERROR = .TRUE. ERRNUM = 5 else ! ! This do loop is not standard Fortran. ! do I = 1, NADDRSS if ( (CNDTN(I).ne.'X') & .and.(CNDTN(I).ne.'1') & .and.(CNDTN(I).ne.'0') ) then ERROR = .TRUE. ERRNUM = 10 end if end do end if end if ! ! Process first line and read and process other lines until end of data or ! an error occurs. This would be a while loop in non-standard Fortran. ! 10 if ((DONE).or.(ERROR)) goto 20 ! ! Translate BOUT into HOUT. ! HOUT(1:1) = BI2HEX(BOUT(1)) HOUT(2:2) = BI2HEX(BOUT(2)) if ((HOUT(1:1).eq.'G').or.(HOUT(2:2).eq.'G')) then ERROR = .TRUE. ERRNUM = 6 end if ! ! Search addresses for those matching the condtions and fill the corresponding ! location in the MHEXA array with the current output value. This unlabeled ! do loop is not stanadard Fortran. ! if (.not.ERROR) then DO J = 0, LASTELMT MATCH = .TRUE. I = 1 ! ! The following could be a while loop in non-standard Fortran. ! 30 if ((.not.MATCH).or.(I.gt.NADDRSS)) goto 40 if ((CNDTN(I).ne.'X').and.(CNDTN(I).ne.ADDRSBIT(J,I))) & MATCH = .FALSE. I = I + 1 goto 30 40 continue ! if (MATCH) MHEXA(J) = HOUT end do end if ! ! Read next line from state table (.STF) file. Watch for end of file. ! if (.not.ERROR) then LINE = LINE + 1 read(INUNIT, INFRMT, IOSTAT=IOSTAT) & (CNDTN(I), I = NADDRSS,1,-1), & (BOUT(I), I = 1,2) if (IOSTAT.eq.-1) then DONE = .TRUE. else if (IOSTAT.lt.-1) then ERROR = .TRUE. ERRNUM = 5 else ! ! This do loop is not stanrdard Fortran ! do I = 1, NADDRSS if ( (CNDTN(I).ne.'X') & .and.(CNDTN(I).ne.'1') & .and.(CNDTN(I).ne.'0') ) then ERROR = .TRUE. ERRNUM = 10 end if end do end if end if ! goto 10 20 continue ! ! End of while loop - Done reading and processing data. Echo number of lines ! of state table data read. ! if (.not.ERROR) write(*,580) LINE - 4 ! ! Close input file, check for existing output file and, if it exists, ask user ! for permission to replace it, open output file, write hex data, write a final ! CR/LF and close the output file. ! close(INUNIT, IOSTAT=IOSTAT) if (IOSTAT.ne.0) write(*,*) 'Error closing input file', & ' - continuing.' ! if (.not.ERROR) then inquire(file=FSOUT, exist=OLDOUT) if (OLDOUT) then write(*,600) read(*,610) REPLACE write(*,*) if ((REPLACE.ne.'y').and.(REPLACE.ne.'Y')) then ERROR = .TRUE. ERRNUM = 9 end if end if end if ! if (.not.ERROR) then open(unit=OUTUNIT,file=FSOUT,status='UNKNOWN',IOSTAT=IOSTAT) if (IOSTAT.ne.0) then ERROR = .TRUE. ERRNUM = 7 else ! ! This unlabeled do loop is not standard Fortran. ! do J = 0,LASTELMT,16 write(OUTUNIT,570,IOSTAT=IOSTAT) (MHEXA(K), K = J,J+15) if (IOSTAT.ne.0) ERROR = .TRUE. end do ! ! Add final CR/LF to hex file. May be need by EPROM programing software ! write(OUTUNIT,570,IOSTAT=IOSTAT) if (IOSTAT.ne.0) ERROR = .TRUE. if (ERROR) ERRNUM = 8 close(OUTUNIT, IOSTAT=IOSTAT) if (IOSTAT.ne.0) write(*,*) 'Error closing output file', & ' - continuing.' endif end if ! ! Echo number of hex values written. ! if (.not.ERROR) write(*,590) J ! ! Display error or all done message. This block could be replaced with ! a select case block in non-standard Fortran. ! write(*,*) if (ERROR) then if (ERRNUM.eq.1) then write(*,*) 'Can''t open input (.STF) file - aborting.' else if (ERRNUM.eq.2) then write(*,*) 'Can''t read third line of input (.STF) file', & ' - aborting.' else if (ERRNUM.eq.3) then write(*,*) 'Number of address lines must be between 4 and', & ' 14 - aborting.' else if (ERRNUM.eq.4) then write(*,*) 'Can''t convert default output value to hex', & ' - aborting.' else if (ERRNUM.eq.5) then write(*,800) LINE else if (ERRNUM.eq.6) then write(*,810) LINE - 3 else if (ERRNUM.eq.7) then write(*,*) 'Can''t open output (.HEX) file - aborting.' else if (ERRNUM.eq.8) then write(*,*) 'Can''t write to hex output (.HEX) file', & ' - aborting.' else if (ERRNUM.eq.9) then write(*,*) 'Output (.HEX) file exists - aborting.' else if (ERRNUM.eq.10) then write(*,820) LINE - 3 end if else write(*,*) 'Program completed without error.' end if write(*,*) ! stop ! 500 format('0Enter the eight character file name ', & '(without .STF extension): ', \) 510 format(a8) 520 format(a65) 530 format(a13, a65) 540 format(i2, 1x, 2a4) 550 format('0Default output = ', a2, ' hex.', /, & '0', i4, ' address bits used.') 560 format('(', i2, 'a1, 1x, 2a4)') 570 format(a2, 15(1x, a2)) 580 format(' ', i4, ' state table lines processed.') 590 format(' ', i4, ' hex values written.') 600 format('0Output file already exists. Replace it? (y or n) ', \) 610 format(a1) ! 800 format(' Error reading input (.STF) file line ', i4, & ' - aborting.') 810 format(' Illegal output data in state table line ', i4, & ' - aborting.') 820 format(' Illegal condition character in state table line ', i4, & ' - aborting.') ! end ! of ST2HEX ! ! character*1 function BI2HEX(BNRY) ! ! Convert from 4 digit binary value to hexadecimal. See main documentation ! for details. The code below could be replaced with a select case ! structure in non-standard Fortran. ! character*4 BNRY ! if (BNRY.eq.'0000') then BI2HEX = '0' else if (BNRY.eq.'0001') then BI2HEX = '1' else if (BNRY.eq.'0010') then BI2HEX = '2' else if (BNRY.eq.'0011') then BI2HEX = '3' else if (BNRY.eq.'0100') then BI2HEX = '4' else if (BNRY.eq.'0101') then BI2HEX = '5' else if (BNRY.eq.'0110') then BI2HEX = '6' else if (BNRY.eq.'0111') then BI2HEX = '7' else if (BNRY.eq.'1000') then BI2HEX = '8' else if (BNRY.eq.'1001') then BI2HEX = '9' else if (BNRY.eq.'1010') then BI2HEX = 'A' else if (BNRY.eq.'1011') then BI2HEX = 'B' else if (BNRY.eq.'1100') then BI2HEX = 'C' else if (BNRY.eq.'1101') then BI2HEX = 'D' else if (BNRY.eq.'1110') then BI2HEX = 'E' else if (BNRY.eq.'1111') then BI2HEX = 'F' else ! ! If BNRY is invalid, return the error indicator. ! BI2HEX = 'G' end if ! return ! from BI2HEX end ! of BI2HEX ! ! character*1 function ADDRSBIT(ADDR, BIT) ! ! Return the value of the specified bit in the specified address. See main ! documentation for details. This function uses special MS FORTRAN bitwise ! functions that are not standard Fortran. ! integer ADDR, BIT ! ! Subtract 1 from the bit parameter because MS numbers bits from 0 while ! the main program numbers bits from 1. ! if (BTEST(ADDR, (BIT-1))) then ADDRSBIT = '1' else ADDRSBIT = '0' end if ! return ! from ADDRSBIT end ! of ADDRSBIT