100 !   RE-STORE "WF400  "
102 !  25  sep 86  Chris Sutton, Thomas Lago
103 !  10 june 87 Thomas Lago, File Transfer Capabilities
105   !Program to do waterfall plot using  HP 3565S.
106   !
108   !This program call subprogram from the 3565S Sample Programs files.
110   !These next lines were executed to load the subprograms:
112 !  LOADSUB ALL FROM "HW"
114 !  LOADSUB ALL FROM "ICODE"
116 !  DELSUB Icode_debug
118 !  LOADSUB     FROM "LIB"
120 !  LOADSUB     FROM "USER"
122   !
124     DIM Sta$[200] !Will hold HP-IB module's status register response.
126     DIM Id$[40]
128     !some arrays used by the icode assembler:
130     DIM Source$(0:100)[80],Info$(0:100)[40],List$(0:300)[120]
132     INTEGER Object(0:200)
134     !
136     INTEGER I,Amp_pen_num,Big_screen,N
138     COM /Wf/ INTEGER Log_table(0:32766),Spectrum(0:511)
139     COM Center_freq,Span_freq,Input_level
140     COM File_name1$[10]
142     !Some arrays that match HP-IB module blocks:
143     INTEGER Coef(0:4095),Param(0:15)
144     COM INTEGER Freq(0:399)
146     !
147     OUTPUT 2;CHR$(255)&"K"; ! CLEAR SCREEN
148     OUTPUT 2;CHR$(255)&"{"; ! ACTIVATE FUNCTION KEYS
150     Loop=0
151     Center_freq=1620
152     Span_freq=3200
153     Input_level=-50
155 Create_null:!
156     ON KEY 1 LABEL "" GOSUB Dum_dum
157     ON KEY 2 LABEL "RECALL" GOSUB Hamta
158     ON KEY 3 LABEL "STOP" GOSUB Sluta
159     ON KEY 4 LABEL "" GOSUB Dum_dum
160     ON KEY 5 LABEL "CONFIG" GOSUB Create_new
161     ON KEY 6 LABEL "" GOSUB Dum_dum
162     ON KEY 7 LABEL "BDAT -> UBV-FILE" GOSUB Ubv_file
163     ON KEY 8 LABEL "BDAT -> ASCII" GOSUB Data_transfer
164     GOSUB Init
165 !   ON KEY 6 LABEL "SETTINGS" GOSUB Set_frequency
166     IF FNHw_srq THEN GOSUB Handle_error
167     GOSUB Make_icode
168     GOSUB Download_icode
169     GOSUB Start_icode
170     GOSUB Plot_init
171     IF FNHw_srq THEN GOSUB Handle_error
172     T0=TIMEDATE
173     LOOP
174       GOSUB Upload_freq
175       GOSUB Plot_freq
176       IF Stanna THEN GOTO Label1
177       DISP "Spectra per second: ";PROUND(1/(TIMEDATE-T0),-1)
178       T0=TIMEDATE
179       IF FNHw_srq THEN GOSUB Handle_error
180 Label1:!
181     END LOOP
182 !------------------------------------------------------------------------------
183 Set_frequency:! THIS ROUTINE DOESN'T WORK RIGHT NOW !?
187     LINPUT "FREQUENCY SPAN= ?  (0 < FREQUENCY SPAN < 51200) (NO CHANGE=RETURN)",Slask$
188     IF Slask$="" THEN GOTO 192
189     IF NOT 0<Slask<51200 THEN GOTO Set_frequency
190     Slask=VAL(Slask$)
191     Span_freq=Slask
192     LINPUT "CENTER FREQUENCY= ?  (1/2*FREQUENCY SPAN < CENTER FREQUENCY < 51200-1/2*FREQUENCY SPAN) (NO CHANGE=RETURN)",Slask$
193     IF Slask$="" THEN GOTO 204
194     Slask=VAL(Slask$)
195     IF NOT 1/2*Frequency_span<Slask<51200-1/2*Frequency_span THEN GOTO 192
196     Center_freq=Slask
197     LINPUT "WHAT SENSITIVITY DO YOU WANT ? (-52 < SENSITIVITY < 20 ) (NO CHANGE=RETURN)",Slask$
198     IF Slask$="" THEN GOTO 204
199     Slask=VAL(Slask$)
200     IF NOT -52<Slask<20 THEN GOTO 197
201     Input_level=Slask
202     IF FNHw_srq THEN GOSUB Handle_error
205     CALL Hw_mod_cmd(Input1,"CF "&VAL$(Center_freq))
206     CALL Hw_mod_cmd(Input1,"SP "&VAL$(Span_freq))
208     CALL Hw_mod_cmd(Input1,"RNG "&VAL$(Input_level))
209     IF FNHw_srq THEN GOSUB Handle_error
210     GOSUB Plot_init
212     RETURN 
213 !-------------------------------------------------------------------------------
214 Create_new:!
215     ON KEY 1 LABEL "STORE " GOSUB Lagra
216     LINPUT "WHAT SHOULD I CALL THE FILE FOR THE FREQUENCY SPECTRAS ? ",Namn$
217     Name_store$=Namn$
218     LINPUT "HOW MANY SPECTRAS DO YOU WANT TO STORE ?",Antal$
219     Antal=VAL(Antal$)
220     ON ERROR GOSUB Create_failed
221     CREATE BDAT Namn$,Antal*4
222     ASSIGN @File TO Namn$
223     ON ERROR GOSUB Err_routine
224     RETURN 
225 !-------------------------------------------------------------------------------
226 Create_failed:!
227     IF ERRN=54 THEN 
228       ASSIGN @File TO *  ! CLOSE ACTIVE FILE
229        LINPUT "FILE ALREADY EXISTS. OK TO OVERWRITE ? (Y or N)",Slask$
230        IF Slask$="Y" THEN PURGE Namn$
231        IF Slak$="N" THEN 
232           LINPUT "WHAT SHOULD I CALL THE NEW FILE FOR THE FREQUENCY SPECTRAS ? ",Namn$
233           LINPUT "HOW MANY SPECTRAS DO YOU WANT TO STORE ?",Antal$
234           Antal=VAL(Antal$)
235        END IF
236     END IF
237     RETURN 
238 !------------------------------------------------------------------------------
239 Err_routine:!
240     OFF ERROR 
241     DISP ERRN
242     BEEP 
243     RETURN 
244 !-----------------------------------------------------------------------
245 Ubv_file:!
246     Ubv_flag=1
247     GOSUB Data_transfer
248     RETURN 
249 !----------------------------------------------------------------------
250 Dum_dum:!
251     RETURN 
252 !-----------------------------------------------------------------------
253 Lagra:!
254     Stanna=0
255     ON KEY 1 LABEL "" GOSUB Dum_dum
256     ON KEY 2 LABEL "" GOSUB Dum_dum
257     Flagga1=1
258     FOR I=1 TO 10
259         WRITEIO 9826,Lago+156;255
260         WAIT .02
261     NEXT I
262     ASSIGN @File TO Namn$;FORMAT OFF
263     OUTPUT @File;Antal
264     RETURN 
265 !---------------------------------------------------------------------
266 Hamta:!
267     ON KEY 1 LABEL "" GOSUB Dum_dum
268     ON KEY 2 LABEL "" GOSUB Dum_dum
269     OFF KEY 2
270     Stanna=0
271     Name_store$=Namn$
272     LINPUT "WHAT FILE DO YOU WANT TO RECALL ?  (DEFAULT=NORMAL FILE)",Slask$
273     IF Slask$="" THEN GOTO Hamta_2
274     Namn$=Slask$
275  !  OUTPUT 2;CHR$(255)&"K"; ! CLEAR SCREEN
276  !  GOSUB Plot_init
277 Hamta_2:!
278     Flagga2=1
279     FOR I=1 TO 10
280        WRITEIO 9826,Lago+156;255
281        WAIT .02
282     NEXT I
283     ASSIGN @File TO Namn$;FORMAT OFF
284     ENTER @File;Antal
285     ON KEY 4 LABEL "CONTINUE" GOSUB Fortsatt
286     RETURN 
287 !-----------------------------------------------------------------------
288 Fortsatt:!
289     Stanna=0
290     Namn$=Name_store$
291     ON KEY 3 LABEL "STOP" GOSUB Sluta
292     ON KEY 4 LABEL "" GOSUB Dum_dum
293     RETURN 
294 !-------------------------------------------------------------------------
295 Sluta:!
296     Stanna=1
297     Flagga1=0
298     Flagga2=0
299     ON KEY 3 LABEL "" GOSUB Dum_dum
300     ON KEY 4 LABEL "CONTINUE" GOSUB Fortsatt
301     ASSIGN @File TO *
302     RETURN 
303 !-------------------------------------------------------------------------
304 Data_transfer:!
305     OUTPUT 2;CHR$(255)&"K";
306     Stanna=1
307     Xmin=.5*Span_freq-Center_freq
308     Xmax=Center_freq+.5*Span_freq
309     Ymax=Input_level
310     Ymin=Input_level-80
311     LINPUT "WHAT FILE SHOULD I TRANSFER ?  (DEFAULT=THE STORED NAME)",File_name$
312     IF File_name$="" THEN 
313        File_name$=Namn$
314        File_name1$=Namn$
315        GOTO 320
316     END IF
317 Create_next:!
318     LINPUT "DO YOU WANT ANOTHER FILE NAME ? ('Y' IF YOU WANT TO CHANGE NAME)",Slask$
319     IF Slask$="Y" THEN GOSUB Ny_fil
320     LINPUT "WHAT MAS STORAGE UNIT SPECIFIER DO YOU WANT TO USE ? (DEFAULT=:,1401,1)",Slask$
321     IF Slask$="" THEN Slask$=":,1401,1"
322     Spec$=Slask$
323     Svans$="_A"
324     ASSIGN @File TO File_name$
325     ENTER @File;Antal
326     ASSIGN @File TO *
327     File_size=(12*40+402*25.0*Antal)/256
328     IF Ubv_flag THEN File_size=(12*40+402*50.0*Antal)/256
329     ON ERROR GOTO Create_crash
330     GOTO Create_1
331 Ny_fil:!
332     LINPUT "WHAT DO YOU WANT TO CALL THE NEW FILE ?",File_name1$
333     RETURN 
334 !------------------------------------------------------------------------------------
335 Create_crash:!
336     IF ERRN=54 THEN 
337        LINPUT "FILE ALREADY EXISTS. OK TO OVERWRITE ? (Y or N)",Slask$
338        IF Slask$="Y" THEN GOTO Create_noll
339        GOTO Create_next
340     END IF
341 Create_noll:!
342     PURGE File_name1$&Svans$&Spec$
343 Create_1:!
344     CREATE ASCII File_name1$&Svans$&Spec$,File_size
345     ON ERROR GOTO Store_crash
346     ASSIGN @File TO File_name1$&Svans$&Spec$
347     ASSIGN @File2 TO File_name$;FORMAT OFF
348     ENTER @File2;Antal ! GET THE NUMBER OF SPECTRAS
349     DISP "STORING DATA IN FILE ";File_name1$&Svans$&Spec$
350     OUTPUT @File;"SPAMHDR("
351     OUTPUT @File;"  XUNI:Hz"
352     OUTPUT @File;"  YUNI:dB"
353     OUTPUT @File;"  XMIN:";Xmin
354     OUTPUT @File;"  XMAX:";Xmax
355     OUTPUT @File;"  YMIN:";Ymin
356     OUTPUT @File;"  YMAX:";Ymax
357     OUTPUT @File;"  XLOG:"
358     OUTPUT @File;"  YLOG:"
359     OUTPUT @File;"  XDMI:"
360     OUTPUT @File;"  YDMI:"
361     OUTPUT @File;");"
362     N=400
363     IF Ubv_flag THEN 
364         ALLOCATE INTEGER Y(1:N),Y$(1:2*N)[21]
365     ELSE
366         ALLOCATE INTEGER Y(1:N),Y$(1:N)[21]
367     END IF
368     OUTPUT @File;"DATAHDR("
369     OUTPUT @File;"  LBL:WATERFALL,"
370     OUTPUT @File;"  DATE:"&DATE$(TIMEDATE)&","
371     OUTPUT @File;"  OVLD:,"
372     OUTPUT @File;"  DATA#ASCI,";Antal;","
373     FOR I=1 TO Antal
374        ENTER @File2;Block_exponent
375        ENTER @File2;Y(*)  ! GET THE SPECTRA
376        OUTPUT @File;"SPECTRA ";I
377        OUTPUT @File;Block_exponent
378        IF Ubv_flag THEN 
379           FOR J=1 TO N
380              OUTPUT Y$(J*2-1);J
381              OUTPUT Y$(J*2) USING "#,MD.12DESZZZ,A";Y(J),","  !CONVERT THE SPECTRA
382           NEXT J
383        ELSE
384           FOR J=1 TO N
385              OUTPUT Y$(J) USING "#,MD.12DESZZZ,A";Y(J),","  !CONVERT THE SPECTRA
386           NEXT J
387        END IF
388        DISP "I AM TRANSFERING SPECTRA ";I;" RIGHT NOW !   (THERE ARE ";Antal;" SPECTRAS TO MOVE.)"
389        OUTPUT @File;Y$(*)  ! OUTPUT THE SPECTRA IN ASCII
390     NEXT I
391     DISP "I AM READY !"
392     OUTPUT @File;");" ! END
393     ASSIGN @File TO * ! CLOSE
394     ASSIGN @File2 TO * ! CLOSE
395     OUTPUT 2;CHR$(255)&"K"; !CLEAR SCREEN
396     GOSUB Plot_init
397     Stanna=0
398     RETURN 
399 !--------------------------------------------------------------------------------
400 Store_crash:!
401     BEEP 
402     DISP "CRASH !"
403     STOP
404 New_file:!
405     LINPUT "WHAT FILE NAME DO YOU WANT TO USE ?",File_name1$
406     RETURN 
407 !--------------------------------------------------------------------------------
408 Init:   !----------------------------------------------------------
409     !This subprogram initializes the 3565S system and software.
410     CALL Hw_hw                      !to initialize subprograms.
411     CALL Lib_lib
412     CALL Icode_icode
413     !
414     !Initialize LOG look-up table if needed.
415     IF Log_table(3000)=0 THEN CALL Init_log_table(Log_table(*))
416     !
417     CALL Hw_set_dev_sel(711)        !set the 35651A HP-IB address
418     Using_source=0                  !flag.  1= use source 0=don't
419     Source1=1                       !slot number for source.
420     Input1=2  !change in Icode too  !slot number for input.
421     !
422     DISP "Initializing HP3565S hardware"
423     CALL Hw_cmd("ABRT; DISA",10)      !initialize HP-IB module.
424     IF FNHw_io_error THEN CALL User_stop("HP-IB timeout. 3565S not responding.")
425     !Program HP-IB module to pull SRQ on messages, errors, and IRQs.
426     CALL Hw_cmd("RQS "&VAL$(FNHw_str_2_stat("IRQ,ERR")))
427     !
428     !Read status register to clear power-on SRQ and check for errors.
429     Sta$=FNHw_stat_2_str$(VAL(FNHw_cmd_rsp$("STA?")))
430     IF POS(Sta$,"ERR") OR POS(Sta$,"IRQ") THEN GOSUB Handle_error
431     !
432     !Program source1 to output a sine wave
433     IF Using_source THEN 
434       Id$=FNHw_mod_cmd_rsp$(Source1,"ID?",5)
435       IF FNHw_io_error OR (Id$<>"HP35653A") THEN CALL User_stop("35653A not responding.")
436       CALL Hw_mod_cmd(Source1,"RST")           !Reset the source module.
437       CALL Hw_mod_cmd(Source1,"INTR 32")       !Pull IRQ on errors.
438       CALL Hw_mod_cmd(Source1,"OPTM CRND; AM -18")!-20dBVp noise.
439       CALL Hw_mod_cmd(Source1,"ZOOM ON")
440       CALL Hw_mod_cmd(Source1,"SP 200")         !200 Hz Span
441       Noise_freq=100
442       CALL Hw_mod_cmd(Source1,"CF "&VAL$(Noise_freq)) !1KHz
443       CALL Hw_mod_cmd(Source1,"STRT")          !start the source
444     END IF
445     Id$=FNHw_mod_cmd_rsp$(Input1,"ID?",5)
446     IF FNHw_io_error OR (Id$<>"HP35652A") THEN CALL User_stop("35652A not responding.")
447     CALL Hw_mod_cmd(Input1,"RST",10)           !Reset the input module
448     CALL Hw_mod_cmd(Input1,"ZOOM ON")          !Zoom for FFT
449     CALL Hw_mod_cmd(Input1,"CF "&VAL$(Center_freq))
450     CALL Hw_mod_cmd(Input1,"SP "&VAL$(Span_freq))
451     IF Using_source THEN 
452       CALL Hw_mod_cmd(Input1,"RNG -30")
453     ELSE
454       CALL Hw_mod_cmd(Input1,"RNG "&VAL$(Input_level))
455     END IF
456     DISP 
457     RETURN 
458   !
459 Handle_error:  !--------------------------------------------------
460     Sta$=FNHw_stat_2_str$(VAL(FNHw_cmd_rsp$("STA?")))
461     PRINT "HP-IB module status: ";Sta$
462     PRINT "HP-IB module errors: "
463     PRINT FNHw_get_errstr$(VAL(FNHw_cmd_rsp$("err?")))
464     PRINT FNHw_get_errstr$(VAL(FNHw_cmd_rsp$("err?")))
465     PRINT "Input module errors:"
466     PRINT FNHw_mod_cmd_rsp$(Input1,"ERR?",5)
467     PRINT FNHw_mod_cmd_rsp$(Input1,"ERR?",5)
468     IF Using_source THEN 
469       PRINT "Source module errors:"
470       PRINT FNHw_mod_cmd_rsp$(Source1,"ERR?",5)
471       PRINT FNHw_mod_cmd_rsp$(Source1,"ERR?",5)
472     END IF
473     CALL User_stop("3565S harware has errors.  Press Continue.")
474     RETURN 
475     !
476 Make_icode:     !--------------------------------------------------
477     !This Icode program is an infinite loop that does FFTs from
478     !one input module and leaves the spectrum in Freq block.
479     !Each time a Freq block is ready, this program sends a signal
480     !to the host and then pauses.  The host should read the block
481     !and then continue the Icode program.
482     !
483 Icode_program:     !
484     !first define the names of the memory blocks.
485     DATA "DEFBLK_SP   Coef   4096,2    !Coefficient table for FFT"
486     DATA "DEFBLK_SP   Param   128,2    !FFT parameter block"
487     DATA "DEFBLK_SP   Window 1024,2    !Window"
488     DATA "DEFBLK_SP   Time   1024,2    !Time record from input module"
489     DATA "DEFBLK_SP   Fftout 1024,2    !FFT output (32-bit)"
490     DATA "DEFBLK_MAIN Ftemp   512,2    !FFT output (16 bit)"
491     DATA "DEFBLK_MAIN Freq    800,2    !FFT output (16 bit), 800 lines."
492     DATA "DEFBLK_MAIN Block1 2048,2    !512 floating pt."
493     DATA "DEFBLK_MAIN Block2  512,2    !512 short integers."
494     !
495     DATA "CONST Input1  2  !Address of input module."
496     DATA "VAR   Zero    0  !Really a constant."
497     DATA "VAR   Freq_exp 0 !Block exponent of fft_out block."
498     !
499     DATA "!-------------------------------------------------------------"
500     DATA "      C_GOSUB Init          !Initialize modules and thruput"
501     !
502     DATA "      C_GOSUB Start_fft     !Read data from input and start FFT"
503     DATA "Loop: "
504     DATA "      C_GOSUB Finish_fft"
505     DATA "      C_GOSUB Start_fft     !start next one while send-ing last"
506     DATA "      F_WAIT_TO_SIG  Freq_exp !Tell host data is ready"
507     DATA "      C_GOTO Loop           !loop forever"
508     DATA "      C_END"
509     !
510     DATA "!-------------------------------------------------------------"
511     DATA "Start_fft:        !subprogram to read in data and start FFT"
512     DATA "      F_THRUPUT      1,0                   !read input1->Time"
513     DATA "      V_PUT32_INDEXED Param,0,Zero         !init block exponent."
514     DATA "      F_SIG_PROC     4032,0,5,Param,0,Coef,0,Window,0,Time,0,Fftout,0"
515     DATA "      C_RTS"
516     DATA "!------------------------------------------------------------"
517     DATA "Finish_fft:"      !subprogram to do post-fft stuff"
518     DATA "Wloop: C_SP_BEQ       Wloop,2               !wait for FFT done"
519     DATA "      V_GET32_INDEXED Param,0,Freq_exp     !get block exponent."
520     DATA "      V_PUT32_INDEXED ^Fftout,0,Freq_exp   !put block exponent."
521     DATA "      F_INT_TO_SHORT  Fftout,0,Ftemp,0,512"
522     DATA "      V_GET32_INDEXED ^Ftemp,0,Freq_exp     !get block exponent."
523     DATA "        !these 2 moves delete the guard band and swap spectrum"
524     DATA "      F_MOVE_BLOCK    Ftemp,  0,Freq,200,200 !block swap         "
525     DATA "      F_MOVE_BLOCK    Ftemp,312,Freq,  0,200 !block swap         "
526     DATA "      C_RTS"
527     DATA "!------------------------------------------------------------"
528     DATA "Init:             !subprogram to initialize modules and thruput"
529     DATA "      F_EXEC  2"
530     DATA "      F_MOD_COMMAND  Input1,'INTR  32' !Pull IRQ on errors."
531     DATA "      F_MOD_COMMAND  Input1,'RQS 2048' !Pull SRQ when block ava."
532     DATA "      F_MOD_COMMAND  Input1,'STRT'     !Start the input module"
533     DATA "      F_READY_RAM    0,Time,0,1024,1,1,Input1  !setup thruput"
534     DATA "      F_KEEP_READY_RAM"
535     DATA "      F_FLOAT_WINGEN Block1, 0, 512, 2, 0.499984, -.499984"
536     DATA "      F_FLOAT_TO_SHORT Block1, 0, Block2, 0, 512"
537     DATA "      F_SHORT_INTRLVE  Block2, 0, Block2, 0, Window, 0, 512"
538     DATA "      C_RTS"
539     !
540     DATA "EL_COMPLETO"
541     !--------------------------------------------------------------------
542     !
543     !These lines read the above DATA statments into Source$(*) and
544     !call the Icode assembler to get Object(*)
545     RESTORE Icode_program
546     Source_ptr=-1
547     REPEAT
548       Source_ptr=Source_ptr+1
549       READ Source$(Source_ptr)
550     UNTIL POS(UPC$(Source$(Source_ptr)),"EL_COMPLETO")
551     Error_count=FNIcode_assemble(Source$(*),Object(*),1,Info$(*),1,List$(*))
552     IF Error_count<>0 THEN 
553       DISP "Errors during assemble.  Program paused"
554       PAUSE
555     END IF
556     RETURN 
557     !
558 Download_icode:    !-----------------------------------------------------
559     !Now download the Icode program (and allocate blocks)
560     Icode_id=FNIcode_dld(Object(*),1,Info$(*))
561     IF Icode_id<=0 THEN CALL User_stop("Icode download failed.")
562     !
563     !The FFT parameter block must be filled in with initial values.
564     Param(0)=0       !dest_exp MSW
565     Param(1)=0       !dest_exp LSW
566     Param(2)=9       !blk_size_exp: 2^9th for 512pt complex time record
567     Param(3)=0       !overflow_flag
568     Param(4)=0       !swap_flag
569     Param(5)=1       !window_flag
570     Param(6)=2       !IFFT_flag: 2^1=do mag_sq
571     !
572     !Download the FFT parameter block
573     Param_id=FNIcode_ext_id("Param",Info$(*)) !get block id from icode
574     CALL Hw_write_blk(Param_id,Param(*))
575     IF FNHw_io_error THEN CALL User_stop("Param block download failed.")
576     !
577     !Generate and download cosine table used by FFT
578     CALL Lib_fft_coefs(Coef(*))              !generate table
579     Coef_id=FNIcode_ext_id("Coef",Info$(*))  !get block id from icode
580     CALL Hw_write_blk(Coef_id,Coef(*))       !download
581     !
582     Freq_id=FNIcode_ext_id("Freq",Info$(*))  !get block id from icode
583     RETURN 
584   !
585 Start_icode:    !--------------------------------------------------
586     CALL Hw_cmd("PROG "&VAL$(Icode_id))    !Start ICODE program
587     RETURN 
588   !
589 Upload_freq:    !------------------------------------------------
590     !This subroutine waits until the I-code program has a new Freq(*)
591     !block to be uploaded.
592     !
593     IF Stanna THEN RETURN 
594     IF Flagga2 THEN GOTO Upload_2
595     Blk_exponent=VAL(FNHw_cmd_rsp$("WSG?")) !block_expoent is
596                                             !sent back as the signal.
597     CALL Hw_read_blk(Freq_id,Freq(*))       !Upload
598     IF FNHw_io_error THEN CALL User_stop("Freq block upload failed.")
599     IF MIN(Freq(*))<0 THEN CALL User_stop("Error: negative numbers in magnitude squared data from 3565S")
600     IF Flagga1 THEN 
601        OUTPUT @File;Block_exponent
602        OUTPUT @File;Freq(*)
603        Loop=Loop+1
604        IF Loop=Antal THEN 
605           DISP "I AM READY WITH ";Antal;" FREQUENCY SPECTRAS"
606           WAIT .5
607           Flagga1=0
608           ASSIGN @File TO *
609           Loop=0
610           FOR I=1 TO 10
611              WRITEIO 9826,Lago+156;255
612              WAIT .02
613           NEXT I
614           ON KEY 1 LABEL "STORE" GOSUB Lagra
615           ON KEY 2 LABEL "RECALL" GOSUB Hamta
616         END IF
617     END IF
618 Upload_2:!
619     IF Flagga2 THEN 
620        ENTER @File;Block_exponent
621        ENTER @File;Freq(*)
622        Loop=Loop+1
623        IF Loop=Antal THEN 
624           DISP "I AM READY WITH ";Antal;" FREQUENCY SPECTRAS"
625           Stanna=1
626           Flagga2=0
627           ASSIGN @File TO *
628           Loop=0
629           FOR I=1 TO 10
630              WRITEIO 9826,Lago+156;255
631              WAIT .02
632           NEXT I
633           ON KEY 1 LABEL "STORE" GOSUB Lagra
634           ON KEY 2 LABEL "RECALL" GOSUB Hamta
635         END IF
636     END IF
637     IF Using_source THEN 
638       Noise_freq=Noise_freq+300              !increment Source frequency
639       IF Noise_freq>5000 THEN Noise_freq=100
640       CALL Hw_mod_cmd(Source1,"CF "&VAL$(Noise_freq))   !send freq to source
641     END IF
642     RETURN 
643     !
644 Plot_init:      !-------------------------------------------------
645     GINIT
646     PLOTTER IS CRT,"INTERNAL";COLOR MAP
647     SET PEN 1 INTENSITY 1,1,1
648     SET PEN 2 INTENSITY .3,.3,.9
649     SET PEN 3 INTENSITY .3,.5,.8
650     SET PEN 4 INTENSITY .3,.7,.7
651     SET PEN 5 INTENSITY .4,.7,.6
652     SET PEN 6 INTENSITY .4,.8,.4
653     SET PEN 7 INTENSITY .6,.6,.3
654     SET PEN 8 INTENSITY .7,.5,.2
655     SET PEN 9 INTENSITY .8,.6,.2
656     SET PEN 10 INTENSITY .9,.5,.1
657     SET PEN 11 INTENSITY .9,.4,.1
658     SET PEN 12 INTENSITY 1,.3,0
659     GCLEAR
660     G_base=2097152                      !start of graphics memory
661     IF NOT POS(SYSTEM$("CRT ID"),"CGB") THEN CALL User_stop("Incompatible display type.")
662     IF POS(SYSTEM$("CRT ID"),"128") THEN 
663       Big_screen=1
664     ELSE
665       Big_screen=0
666     END IF
667     IF Big_screen THEN 
668       Start_addr=G_base+1024*568.0+150   !start 568 pixels down, 150 over
669       WINDOW 0,1024,-768,0  !same as pixels
670       PEN 1
671       CSIZE 100.0*30/767
672       MOVE 150,-580
673       LORG 3
674       LABEL "\ "&VAL$(Center_freq-Span_freq/2)
675       MOVE 150+400,-580
676       LORG 9
677       LABEL VAL$(Center_freq+Span_freq/2)&" Hz /"
678     ELSE
679       Start_addr=G_base+1024*278.0+150
680       WINDOW 0,1024,-400,0
681       PEN 1
682       CSIZE 100*15/399
683       MOVE 150,-285
684       LORG 3
685       LABEL "\ "&VAL$(Center_freq-Span_freq/2)
686       MOVE 150+400,-285
687       LORG 9
688       LABEL VAL$(Center_freq+Span_freq/2)&" Hz /"
689     END IF
690     WAIT .1
691     CALL Init_scroll(Lago)
692     RETURN 
693 Plot_freq:      !--------------------------------------------------
694     IF Stanna THEN RETURN 
695     CALL Look_up(400,Log_table(*),Freq(*),Spectrum(*))
696     Amp_pen_num=MAX(2,MIN(12,Blk_exponent+17))
697     !
698     !use  one of the next two lines:
699 !   CALL Mwrite(Start_addr,1,-1024,Amp_pen_num,399,Spectrum(*)) !solidcolor
700     CALL Mwrite(Start_addr,2,-1024,2,399,Spectrum(*))           !rainbow
701     !
702     CALL Mwrite(Start_addr,0,-1024,1,399,Spectrum(*))           !border
703     IF (Time_counter>5) AND (TIMEDATE-Last_time>5) THEN 
704       IF Big_screen THEN 
705         PRINT TABXY(3,35);
706       ELSE
707         PRINT TABXY(1,16);
708       END IF
709       PRINT TIME$(TIMEDATE)
710       Time_counter=0
711       Last_time=INT(TIMEDATE)
712     ELSE
713       Time_counter=Time_counter+1
714     END IF
715     WRITEIO 9826,Lago+156;255 !Scroll th display
716     RETURN 
717     END
718  !-----------------------------------------------------------------
719 Init_log_table:SUB Init_log_table(INTEGER Log_table(*))
720       INTEGER I,Max_pen,Max_i
721       DISP "Initializing log table"
722       Max_amp=31
723       Min_amp=3
724       Max_i=7000
725       MAT Log_table= (Max_amp)
726       Log_table(0)=Min_amp
727       Fudge_factor=(Max_amp-Min_amp-1)/LGT(Max_i)
728       FOR I=1 TO Max_i
729         Log_table(I)=1+LGT(I)*Fudge_factor+Min_amp
730       NEXT I
731       DISP 
732     SUBEND
733  !-----------------------------------------------------------------
734     SUB Init_scroll(Lago)
735       Lago=5652480
736      ! SOURCE
737       Xs=5
738       Ys=4
739      ! DESTINATION
740       Xd=9
741       Yd=3
742      ! WIDTH OF THE SCREEN TO BE MOVED
743       Bredd=1000
744      ! HEIGHT OF THE SCREEN TO BE MOVED
745       IF POS(SYSTEM$("CRT ID"),"128") THEN 
746         Hojd=570
747         Xd=6
748       ELSE
749         Hojd=280
750       END IF
751   ! REPLACEMENT RULE
752       WRITEIO 9826,Lago+238;3
753       WRITEIO 9826,Lago+136;255
754   ! SOURCE COORDINATES
755       WRITEIO -9826,Lago+242;Xs
756       WRITEIO -9826,Lago+246;Ys
757   ! DESTINATION COORDINATES
758       WRITEIO -9826,Lago+250;Xd
759       WRITEIO -9826,Lago+254;Yd
760   ! WIDTH
761       WRITEIO -9826,Lago+258;Bredd
762   ! HEIGHT
763       WRITEIO -9826,Lago+262;Hojd
764    !
765     SUBEND
766   CSUB Mwrite(Start_addr,INTEGER Fill_mode,Offset,Pen_num,Num_pts,D_array(*))
767   CSUB Look_up(INTEGER Num_pts,Table(*),Inn(*),Out(*))
768 Hw_hw:SUB Hw_hw
769  !
770  !      This subprogram is used to initialize the  HP3565S  demo  programs
771  !      hardware  interface file.  Note that Hw_hw does not initialize the
772  !      device selector address of the HP3565S hardware.
773  !
774     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
775     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
776     Io_error=0
777     Hpib_addr=0
778     Sel_code=7
779     ASSIGN @Hpib_mod TO 700
780     ASSIGN @Bin_hpib_mod TO 700;FORMAT OFF
781   SUBEND
782   !
783 Hw_cmd:SUB Hw_cmd(Op_string$,OPTIONAL Timeout_time)
784  !
785  !      This  subprogram  is  used  to  send a command string to the HP-IB
786  !      module.  The command string sent  is  specified  by  <Op_string$>.
787  !      <Timeout_time>  is an optional timeout parameter in seconds.
788  !
789     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
790     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
791     Io_error=0
792     ON ERROR GOTO Hw_io_error
793     IF NPAR=2 THEN 
794       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
795     END IF
796     OUTPUT @Hpib_mod;Op_string$
797     IF 0 THEN 
798 Hw_io_error:Io_error=1
799     END IF
800   SUBEND
801   !
802 Hw_rsp:DEF FNHw_rsp$(OPTIONAL Timeout_time)
803 !
804 !      This function is used to read a response from HP-IB module.   This
805 !      function returns the response to the caller in the function result
806 !      string.   <Timeout_time>  is  an  optional  timeout  parameter  in
807 !      seconds.
808 !
809     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
810     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
811     DIM Temp$[255]
812     Io_error=0
813     ON ERROR GOTO Hw_io_error
814     IF NPAR=1 THEN 
815       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
816     END IF
817     ENTER @Hpib_mod;Temp$
818     IF 0 THEN 
819 Hw_io_error:!
820       Io_error=1
821       Temp$=""
822     END IF
823     RETURN Temp$
824   FNEND
825   !
826 Hw_cmd_rsp:DEF FNHw_cmd_rsp$(Op_string$,OPTIONAL Timeout_time)
827  !
828  !      This function is used to send a command string to the HP-IB module
829  !      and read a response string back from then HP-IB module.  First the
830  !      command string, specified by <Op_string$>, is sent  to  the  HP-IB
831  !      module.   Then  a  response  is  read back from then HP-IB module.
832  !      This function returns the response to the caller in  the  function
833  !      result string.  <Timeout_time> is an optional timeout parameter in
834  !      seconds.
835  !
836     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
837     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
838     DIM Temp$[255]
839     Io_error=0
840     ON ERROR GOTO Hw_io_error
841     IF NPAR=2 THEN 
842       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
843     END IF
844     OUTPUT @Hpib_mod;Op_string$
845     ENTER @Hpib_mod;Temp$
846     IF 0 THEN 
847 Hw_io_error:!
848       Io_error=1
849       Temp$=""
850     END IF
851     RETURN Temp$
852   FNEND
853   !
854 Hw_mod_cmd:SUB Hw_mod_cmd(Mf_mod,Op_string$,OPTIONAL Timeout_time)
855  !
856  !      This  function is used to send a command string to an input module
857  !      or an source module.  The module address is specified by <mf_mod>.
858  !      The command string  to  be  sent  is  specified  by  <op_string$>.
859  !      <Timeout_time>  is an optional timeout parameter in seconds.
860  !
861     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
862     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
863     Io_error=0
864     ON ERROR GOTO Hw_io_error
865     IF NPAR=3 THEN 
866       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
867     END IF
868     OUTPUT @Hpib_mod;"WCM ";Mf_mod;",'";Op_string$;"'"
869     IF 0 THEN 
870 Hw_io_error: !
871       Io_error=1
872     END IF
873   SUBEND
874   !
875 Hw_mod_rsp:DEF FNHw_mod_rsp$(Mf_mod,OPTIONAL Timeout_time)
876  !
877  !      This  function  is  used  to  read a response string from an input
878  !      module or an source module.   The module is specified by <mf_mod>.
879  !      The  response  is  returned  to  the caller in the function result
880  !      string.   <Timeout_time>  is  an  optional  timeout  parameter  in
881  !      seconds.
882  !
883     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
884     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
885     DIM Temp$[255]
886     Io_error=0
887     ON ERROR GOTO Hw_io_error
888     IF NPAR=2 THEN 
889       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
890     END IF
891     OUTPUT @Hpib_mod;"RRSP ";Mf_mod
892     ENTER @Hpib_mod;Temp$
893     IF 0 THEN 
894 Hw_io_error: !
895       Io_error=1
896       Temp$=""
897     END IF
898     RETURN Temp$
899   FNEND
900   !
901 Hw_mod_cmd_rsp:DEF FNHw_mod_cmd_rsp$(Mf_mod,Op_string$,OPTIONAL Timeout_time)
902 !
903 !      This function is used to send a command string to an input  module
904 !      or  an  source  module,  and  read a string response back from the
905 !      specified module.   The module address is specified  by  <mf_mod>.
906 !      First,   the   specified   module   is  sent  the  command  string
907 !      <op_string$>.    Then,  the  response  string  is  read  from  the
908 !      specified  module  and returned to the host in the function result
909 !      string.   <Timeout_time>  is  an  optional  timeout  parameter  in
910 !      seconds.
911 !
912     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
913     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
914     DIM Temp$[255]
915     Io_error=0
916     ON ERROR GOTO Hw_io_error
917     IF NPAR=3 THEN 
918       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
919     END IF
920     OUTPUT @Hpib_mod;"WCM ";Mf_mod;",'";Op_string$;"'"
921     OUTPUT @Hpib_mod;"RRSP ";Mf_mod
922     ENTER @Hpib_mod;Temp$
923     IF 0 THEN 
924 Hw_io_error: !
925       Io_error=1
926       Temp$=""
927     END IF
928     RETURN Temp$
929   FNEND
930   !
931 Hw_gbl_cmd:SUB Hw_gbl_cmd(Class,Op_string$,OPTIONAL Timeout_time)
932  !
933  !      This subprogram is used to send a global class command  string  to
934  !      all  modules  in  a specified class.   All modules in the fast bus
935  !      class specified  by  <class>  will  be  sent  the  command  string
936  !      <op_string$>.   For  information  on  global  classes, see HP3565S
937  !      module  documentation.   <Timeout_time>  is  an  optional  timeout
938  !      parameter in seconds.
939  !
940     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
941     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
942     Io_error=0
943     ON ERROR GOTO Hw_io_error
944     IF NPAR=3 THEN 
945       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
946     END IF
947     OUTPUT @Hpib_mod;"WGCM ";Class;",'";Op_string$;"'"
948     IF 0 THEN 
949 Hw_io_error: !
950       Io_error=1
951     END IF
952   SUBEND
953   !
954 Hw_write_blk:SUB Hw_write_blk(Block_id,INTEGER Block_array(*),OPTIONAL Timeout_time)
955  !
956  !      This function is used to write a short integer data array  into  a
957  !      HP-IB module data RAM block.   All short integer data in the array
958  !      <block_array(*)> will be downloaded into the HP-IB module data RAM
959  !      block specified by  <block_id>.   <Timeout_time>  is  an  optional
960  !      timeout parameter in seconds.
961  !
962     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
963     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
964     Io_error=0
965     ON ERROR GOTO Hw_io_error
966     IF NPAR=3 THEN 
967       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
968     END IF
969     Block_size=FNLib_sizeof(Block_array(*))
970     OUTPUT @Hpib_mod USING "#,K";"WBLD ";Block_id;",";Block_size;",#I"
971     OUTPUT @Bin_hpib_mod;Block_array(*)
972     IF 0 THEN 
973 Hw_io_error: !
974       Io_error=1
975     END IF
976   SUBEND
977   !
978 Hw_read_blk:SUB Hw_read_blk(Block_id,INTEGER Block_array(*),OPTIONAL Timeout_time)
979  !
980  !      This  subprogram is used to read a short integer data block from a
981  !      HP-IB module data RAM block.  Short integer data will be read from
982  !      the data RAM block specified by <block_id> until the short integer
983  !      array <block_array(*)> is full.   <Timeout_time>  is  an  optional
984  !      timeout parameter in seconds.
985  !
986     COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
987     COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
988     INTEGER Pound_i
989     REAL Block_size
990     Io_error=0
991     ON ERROR GOTO Hw_io_error
992     IF NPAR=3 THEN 
993       IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
994     END IF
995     Block_size=FNLib_sizeof(Block_array(*))
996     OUTPUT @Hpib_mod;"RBLD ";Block_id;",";Block_size
997     ENTER @Hpib_mod USING "#,W";Pound_i
998     IF Pound_i<>9033 THEN 
999       Io_error=1
1000      OUTPUT @Hpib_mod;" "
1001    ELSE
1002      ENTER @Bin_hpib_mod;Block_array(*)
1003    END IF
1004    IF 0 THEN 
1005 Hw_io_error:!
1006      Io_error=1
1007    END IF
1008  SUBEND
1009  !
1010 Hw_enter_blk:SUB Hw_enter_blk(INTEGER Block_array(*),OPTIONAL Timeout_time)
1011!
1012!      This  subprogram is used to read a short integer data array from a
1013!      running  ICODE  program.    See  HP-IB  module  documentation  for
1014!      information  on  how  ICODE  can  send  data  to  the host.   This
1015!      subprogram uses  the  HP-IB  module  RBLK  HP-IB  command.   After
1016!      sending the RBLK command, data is read from HP-IB and put into the
1017!      short   integer  array  <block_array(*)>.    Data  is  read  until
1018!      <Block_array(*)> is full.   <Timeout_time> is an optional  timeout
1019!      parameter in seconds.
1020!
1021    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1022    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1023    INTEGER Pound_i
1024    Io_error=0
1025    ON ERROR GOTO Hw_io_error
1026    IF NPAR=2 THEN 
1027      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1028    END IF
1029    OUTPUT @Hpib_mod;"RBLK"
1030    ENTER @Hpib_mod USING "#,W";Pound_i
1031    IF Pound_i<>9033 THEN 
1032      Io_error=1
1033      OUTPUT @Hpib_mod;" "
1034    ELSE
1035      ENTER @Bin_hpib_mod;Block_array(*)
1036    END IF
1037    IF 0 THEN 
1038 Hw_io_error:!
1039      Io_error=1
1040    END IF
1041  SUBEND
1042  !
1043 Hw_output_blk:SUB Hw_output_blk(INTEGER Block_array(*),OPTIONAL Timeout_time)
1044!
1045!      This subprogram is used to send a short integer data  array  to  a
1046!      running ICODE program.  For information on ICODE and how ICODE can
1047!      accept  a  block  of  data, see HP-IB module documentation.   This
1048!      subprogram uses  the  HP-IB  module  WBLK  HP-IB  command.   After
1049!      issuing  the  WBLK  command,  the  data in the short integer array
1050!      <block_array(*)> is sent to HP-IB module.   <Timeout_time>  is  an
1051!      optional  timeout  parameter in seconds.
1052!
1053    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1054    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1055    INTEGER Pound_i
1056    Io_error=0
1057    ON ERROR GOTO Hw_io_error
1058    IF NPAR=2 THEN 
1059      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1060    END IF
1061    OUTPUT @Hpib_mod USING "#,K";"WBLK #I"
1062    OUTPUT @Bin_hpib_mod;Block_array(*)
1063    IF 0 THEN 
1064 Hw_io_error:!
1065      Io_error=1
1066    END IF
1067  SUBEND
1068  !
1069 Hw_read_mod_blk:SUB Hw_read_mod_blk(Mf_mod,INTEGER Block_array(*),OPTIONAL Timeout_time)
1070 !
1071 !      This subprogram is used to read a short integer data block from an
1072 !      input module.   This subprogram uses the HP-IB module RDT command.
1073 !      Data  is  read from the module specified by <mf_mod> and placed in
1074 !      <Block_array(*)>.   Data is read until <Block_array(*)>  is  full.
1075 !      <Timeout_time>  is an optional timeout parameter in seconds.
1076 !
1077    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1078    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1079    INTEGER Pound_i
1080    REAL Block_size
1081    Io_error=0
1082    ON ERROR GOTO Hw_io_error
1083    IF NPAR=3 THEN 
1084      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1085    END IF
1086    Block_size=FNLib_sizeof(Block_array(*))
1087    OUTPUT @Hpib_mod;"RDT ";Mf_mod;",";Block_size
1088    ENTER @Hpib_mod USING "#,W";Pound_i
1089    IF Pound_i<>9033 THEN 
1090      Io_error=1
1091      OUTPUT @Hpib_mod;" "
1092    ELSE
1093      ENTER @Bin_hpib_mod;Block_array(*)
1094    END IF
1095    IF 0 THEN 
1096 Hw_io_error:!
1097      Io_error=1
1098    END IF
1099  SUBEND
1100  !
1101 Hw_write_fblk:SUB Hw_write_fblk(Block_id,Block_array(*),OPTIONAL Timeout_time)
1102 !
1103 !      This  function is used to write a floating point data array into a
1104 !      HP-IB module data RAM block.  All floating point data in the array
1105 !      <block_array(*)> will be downloaded into the HP-IB module data RAM
1106 !      block specified by  <block_id>.   <Timeout_time>  is  an  optional
1107 !      timeout parameter in seconds.
1108 !
1109    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1110    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1111    Io_error=0
1112    ON ERROR GOTO Hw_io_error
1113    IF NPAR=3 THEN 
1114      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1115    END IF
1116    Block_size=FNLib_fsizeof(Block_array(*))*4
1117    OUTPUT @Hpib_mod USING "#,K";"WBLD ";Block_id;",";Block_size;",#I"
1118    OUTPUT @Bin_hpib_mod;Block_array(*)
1119    IF 0 THEN 
1120 Hw_io_error:!
1121      Io_error=1
1122    END IF
1123  SUBEND
1124 Hw_read_fblk:SUB Hw_read_fblk(Block_id,Block_array(*),OPTIONAL Timeout_time)
1125 !
1126 !      This subprogram is used to read a floating point data block from a
1127 !      HP-IB  module  data  RAM block.   Floating point data will be read
1128 !      from the data RAM block specified by <block_id> until the floating
1129 !      point  array  <block_array(*)>  is  full.   <Timeout_time>  is  an
1130 !      optional  timeout  parameter in seconds.
1131 !
1132    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1133    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1134    INTEGER Pound_i,I
1135    REAL Block_size
1136    Io_error=0
1137    ON ERROR GOTO Hw_io_error
1138    IF NPAR=3 THEN 
1139      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1140    END IF
1141    Block_size=FNLib_fsizeof(Block_array(*))*4
1142    OUTPUT @Hpib_mod;"RBLD ";Block_id;",";Block_size
1143    ENTER @Hpib_mod USING "#,W";Pound_i
1144    IF Pound_i<>9033 THEN 
1145      Io_error=1
1146      OUTPUT @Hpib_mod;" "
1147    ELSE
1148      ENTER @Bin_hpib_mod;Block_array(*)
1149    END IF
1150    IF 0 THEN 
1151 Hw_io_error:!
1152      Io_error=1
1153    END IF
1154  SUBEND
1155 !
1156 Hw_enter_fblk:SUB Hw_enter_fblk(Block_array(*),OPTIONAL Timeout_time)
1157!
1158!      This subprogram is used to read a floating point data array from a
1159!      running  ICODE  program.    See  HP-IB  module  documentation  for
1160!      information on  how  ICODE  can  send  data  to  the  host.   This
1161!      subprogram  uses  the  HP-IB  module  RBLK  HP-IB command.   After
1162!      sending the RBLK command, data is read from HP-IB and put into the
1163!      floating  point  array  <Block_array(*)>.    Data  is  read  until
1164!      <block_array(*)>  is full.   <Timeout_time> is an optional timeout
1165!      parameter in seconds.
1166!
1167    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1168    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1169    INTEGER Pound_i
1170    Io_error=0
1171    ON ERROR GOTO Hw_io_error
1172    IF NPAR=2 THEN 
1173      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1174    END IF
1175    OUTPUT @Hpib_mod;"RBLK"
1176    ENTER @Hpib_mod USING "#,W";Pound_i
1177    IF Pound_i<>9033 THEN 
1178      Io_error=1
1179      OUTPUT @Hpib_mod;" "
1180    ELSE
1181      ENTER @Bin_hpib_mod;Block_array(*)
1182    END IF
1183    IF 0 THEN 
1184 Hw_io_error:!
1185      Io_error=1
1186    END IF
1187  SUBEND
1188  !
1189 Hw_output_fblk:SUB Hw_output_fblk(Block_array(*),OPTIONAL Timeout_time)
1190!
1191!      This subprogram is used to send a floating point data array  to  a
1192!      running ICODE program.  For information on ICODE and how ICODE can
1193!      accept  a  block  of  data, see HP-IB module documentation.   This
1194!      subprogram uses  the  HP-IB  module  WBLK  HP-IB  command.   After
1195!      issuing  the  WBLK  command,  the data in the floating point array
1196!      <block_array(*)> is sent to HP-IB module.   <Timeout_time>  is  an
1197!      optional  timeout  parameter in seconds.
1198!
1199    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1200    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1201    INTEGER Pound_i
1202    Io_error=0
1203    ON ERROR GOTO Hw_io_error
1204    IF NPAR=2 THEN 
1205      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1206    END IF
1207    OUTPUT @Hpib_mod USING "#,K";"WBLK #I"
1208    OUTPUT @Bin_hpib_mod;Block_array(*)
1209    IF 0 THEN 
1210 Hw_io_error:!
1211      Io_error=1
1212    END IF
1213  SUBEND
1214  !
1215 Hw_wait_mod_rdy:SUB Hw_wait_mod_rdy(Mf_mod,OPTIONAL Timeout_time)
1216!
1217!      This  subprogram is used to hold off execution of the host program
1218!      until a specified HP3565S input module or source module is  ready.
1219!      When  the  HP3565S  module specified by <mf_mod> has its ready bit
1220!      asserted, this subprogram will terminate, returning host processor
1221!      control to the caller.   <Timeout_time>  is  an  optional  timeout
1222!      parameter in seconds.
1223!
1224    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1225    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1226    INTEGER Status,Timeout_active
1227    REAL Start_time
1228    Io_error=0
1229    ON ERROR GOTO Hw_io_error
1230    Timeout_active=0
1231    IF NPAR=2 THEN 
1232      IF Timeout_time>0 THEN Timeout_active=1
1233    END IF
1234    IF Timeout_active THEN 
1235      ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1236      Start_time=TIMEDATE
1237      REPEAT
1238        OUTPUT @Hpib_mod;"RMST ";Mf_mod
1239        ENTER @Hpib_mod;Status
1240        IF BIT(Status,4) THEN SUBEXIT
1241      UNTIL ABS(TIMEDATE-Start_time)>Timeout_time
1242    ELSE
1243      REPEAT
1244        OUTPUT @Hpib_mod;"RMST ";Mf_mod
1245        ENTER @Hpib_mod;Status
1246        IF BIT(Status,4) THEN SUBEXIT
1247      UNTIL 1=0
1248      SUBEXIT
1249    END IF
1250 Hw_io_error:Io_error=1
1251  SUBEND
1252  !
1253 Hw_wait_gbl_rdy:SUB Hw_wait_gbl_rdy(OPTIONAL Timeout_time)
1254!
1255!      This  subprogram is used to hold off execution of the host program
1256!      until all HP3565S input modules  and  source  modules  are  ready.
1257!      When  all HP3565S modules (except the HP-IB module)  have asserted
1258!      their ready bits, this subprogram will terminate,  returning  host
1259!      processor  control to the caller.   This subprogram uses the HP-IB
1260!      module  RGSS  command.   <Timeout_time>  is  an  optional  timeout
1261!      parameter in seconds.
1262!
1263    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1264    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1265    INTEGER Status,Timeout_active
1266    REAL Start_time
1267    Io_error=0
1268    ON ERROR GOTO Hw_io_error
1269    Timeout_active=0
1270    IF NPAR=1 THEN 
1271      IF Timeout_time>0 THEN Timeout_active=1
1272    END IF
1273    IF Timeout_active THEN 
1274      ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1275      Start_time=TIMEDATE
1276      REPEAT
1277        OUTPUT @Hpib_mod;"RGSS"
1278        ENTER @Hpib_mod;Status
1279        IF BIT(Status,4) THEN SUBEXIT
1280      UNTIL ABS(TIMEDATE-Start_time)>Timeout_time
1281    ELSE
1282      REPEAT
1283        OUTPUT @Hpib_mod;"RGSS"
1284        ENTER @Hpib_mod;Status
1285        IF BIT(Status,4) THEN SUBEXIT
1286      UNTIL 1=0
1287    END IF
1288 Hw_io_error:Io_error=1
1289  SUBEND
1290  !
1291 Hw_mod_rst:SUB Hw_mod_rst(Mf_mod,OPTIONAL Timeout_time)
1292!
1293!      This  subprogram  is  used  to  reset an input module or an source
1294!      module.  The module to reset is specified by <mf_mod>.  The module
1295!      is reset through the use  of  the  HP-IB  module  RST  n  command.
1296!      <Timeout_time>  is an optional timeout parameter in seconds.
1297 !
1298    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1299    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1300    Io_error=0
1301    ON ERROR GOTO Hw_io_error
1302    IF NPAR=2 THEN 
1303      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1304    END IF
1305    OUTPUT @Hpib_mod;"RST ";Mf_mod
1306    IF 0 THEN 
1307 Hw_io_error:Io_error=1
1308    END IF
1309  SUBEND
1310  !
1311 Hw_gbl_mod_rst:SUB Hw_gbl_mod_rst(OPTIONAL Timeout_time)
1312 !
1313 !      This  subprogram is used to reset all modules on the fast bus (not
1314 !      the HP-IB module).  This is equivalent to a power on state for the
1315 !      modules reset.  <Timeout_time> is an optional timeout parameter in
1316 !      seconds.
1317 !
1318    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1319    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1320    Io_error=0
1321    ON ERROR GOTO Hw_io_error
1322    IF NPAR=1 THEN 
1323      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1324    END IF
1325    OUTPUT @Hpib_mod;"RCF;TCF"     ! this resets all inpt/srce modules
1326    IF 0 THEN 
1327 Hw_io_error:Io_error=1
1328    END IF
1329  SUBEND
1330  !
1331 Hw_rmst:DEF FNHw_rmst(Mf_mod,OPTIONAL Timeout_time)
1332!
1333!      This function is used to get the module  status  register  of  the
1334!      specified input module or source module.   The module is specified
1335!      by <mf_mod>.   The value of the specified module's status register
1336!      is  returned to the caller in the function result.   This function
1337!      makes use of the HP-IB module RMST command.   <Timeout_time> is an
1338!      optional  timeout  parameter in seconds.
1339!
1340    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1341    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1342    Io_error=0
1343    ON ERROR GOTO Hw_io_error
1344    IF NPAR=2 THEN 
1345      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1346    END IF
1347    OUTPUT @Hpib_mod;"RMST ";Mf_mod
1348    ENTER @Hpib_mod;Temp
1349    IF 0 THEN 
1350 Hw_io_error:!
1351      Io_error=1
1352      Temp=0
1353    END IF
1354    RETURN Temp
1355  FNEND
1356  !
1357 Hw_gbl_rmst:DEF FNHw_gbl_rmst(OPTIONAL Timeout_time)
1358 !
1359 !      This  function  is  used to read the global fast bus module status
1360 !      register.   For information on the global fast bus  module  status
1361 !      register, see RGSS in HP-IB module documentation.  The global fast
1362 !      bus  module  status  register  is  returned  to  the caller as the
1363 !      function result.   <Timeout_time> is an optional timeout parameter
1364 !      in seconds.
1365 !
1366    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1367    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1368    Io_error=0
1369    ON ERROR GOTO Hw_io_error
1370    IF NPAR=1 THEN 
1371      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1372    END IF
1373    OUTPUT @Hpib_mod;"RGSS"
1374    ENTER @Hpib_mod;Temp
1375    IF 0 THEN 
1376 Hw_io_error:!
1377      Io_error=1
1378      Temp=0
1379    END IF
1380    RETURN Temp
1381  FNEND
1382  !
1383 Hw_sel_abort:SUB Hw_sel_abort
1384!
1385!      This function is used to cease activity on  the  HP-IB  interface.
1386!      If  the host is not currently the active HP-IB controller, then it
1387!      (the host) will assume active control.   This is equivalent to the
1388!      BASIC ABORT command.
1389!
1390    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1391    Io_error=0
1392    ON ERROR GOTO Hw_io_error
1393    ABORT Sel_code
1394    IF 0 THEN 
1395 Hw_io_error:Io_error=1
1396    END IF
1397  SUBEND
1398  !
1399 Hw_wait_srq:SUB Hw_wait_srq(OPTIONAL Timeout_time)
1400!
1401!      This  subprogram is used to hold off execution of the host program
1402!      until the HP-IB SRQ line is asserted.   When the HP-IB SRQ line is
1403!      asserted, this subprogram will terminate, returning host processor
1404!      control  to  the  caller.   <Timeout_time>  is an optional timeout
1405!      parameter in seconds.
1406!
1407    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1408    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1409    INTEGER Status,Timeout_active
1410    REAL Start_time
1411    ON ERROR GOTO Hw_io_error
1412    Timeout_active=0
1413    IF NPAR=1 THEN 
1414      IF Timeout_time>0 THEN Timeout_active=1
1415    END IF
1416    IF Timeout_active THEN 
1417      Start_time=TIMEDATE
1418      REPEAT
1419        STATUS Sel_code,7;Status
1420        IF BIT(Status,10) THEN SUBEXIT
1421      UNTIL ABS(TIMEDATE-Start_time)>Timeout_time
1422    ELSE
1423      REPEAT
1424        STATUS Sel_code,7;Status
1425        IF BIT(Status,10) THEN SUBEXIT
1426      UNTIL 1=0
1427    END IF
1428 Hw_io_error:Io_error=1
1429  SUBEND
1430  !
1431 Hw_wait_cntrlr:SUB Hw_wait_cntrlr(OPTIONAL Timeout_time)
1432!
1433!      This  subprogram is used to hold off execution of the host program
1434!      until the host becomes the active HP-IB bus controller.  When  the
1435!      host  becomes  the  active  controller  of  the  HP-IB  bus,  this
1436!      subprogram will terminate, returning host processor control to the
1437!      caller.   <Timeout_time>  is  an  optional  timeout  parameter  in
1438!      seconds.
1439!
1440    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1441    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1442    INTEGER Status,Timeout_active
1443    REAL Start_time
1444    Io_error=0
1445    ON ERROR GOTO Hw_io_error
1446    Timeout_active=0
1447    IF NPAR=1 THEN 
1448      IF Timeout_time>0 THEN Timeout_active=1
1449    END IF
1450    IF Timeout_active THEN 
1451      Start_time=TIMEDATE
1452      REPEAT
1453        STATUS Sel_code,6;Status
1454        IF BIT(Status,6) THEN SUBEXIT
1455      UNTIL ABS(TIMEDATE-Start_time)>Timeout_time
1456    ELSE
1457      REPEAT
1458        STATUS Sel_code,6;Status
1459        IF BIT(Status,6) THEN SUBEXIT
1460      UNTIL 1=0
1461    END IF
1462 Hw_io_error:Io_error=1
1463  SUBEND
1464  !
1465 Hw_io_error:DEF FNHw_io_error
1466 !
1467 !      This function is used to see if an error occurred during the  last
1468 !      activation  of  a  hardware  interface  subprogram.   A timeout is
1469 !      considered an error.  Returned as the function result is a boolean
1470 !      with a value of true if an error or timeout did occur.
1471 !
1472    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1473    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1474    INTEGER Temp
1475    Temp=Io_error
1476    Io_error=0
1477    RETURN Temp
1478  FNEND
1479  !
1480 Hw_srq:DEF FNHw_srq
1481 !
1482 !      This function is used to see if the HP-IB SRQ  line  is  currently
1483 !      being  asserted.   Returned  in  the  function result is a boolean
1484 !      value of true if the HP-IB SRQ line is currently being asserted.
1485 !
1486    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1487    INTEGER Status
1488    Io_error=0
1489    ON ERROR GOTO Hw_io_error
1490    STATUS Sel_code,7;Status
1491    IF 0 THEN 
1492 Hw_io_error:!
1493      Io_error=1
1494      Status=0
1495    END IF
1496    RETURN BIT(Status,10)
1497  FNEND
1498  !
1499 Hw_cntrlr:DEF FNHw_cntrlr
1500 !
1501 !      This  function  is used to see if the host is currently the active
1502 !      controller of the HP-IB bus.  Returned in the function result is a
1503 !      boolean with a value of true if the host is currently  the  active
1504 !      controller of the HP-IB bus. Otherwise, false is returned.
1505 !
1506    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1507    INTEGER Status
1508    Io_error=0
1509    ON ERROR GOTO Hw_io_error
1510    STATUS Sel_code,6;Status
1511    IF 0 THEN 
1512 Hw_io_error:!
1513      Io_error=1
1514      Status=0
1515    END IF
1516    RETURN BIT(Status,6)
1517  FNEND
1518  !
1519 Hw_pass_cntrlr:SUB Hw_pass_cntrlr(OPTIONAL Timeout_time)
1520 !
1521 !      The subprogram is used to pass control of the  HP-IB  bus  to  the
1522 !      HP-IB module. What else can I say?
1523 !
1524    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1525    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1526    Io_error=0
1527    ON ERROR GOTO Hw_io_error
1528    IF NPAR=1 THEN 
1529      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1530    END IF
1531    PASS CONTROL @Hpib_mod
1532    IF 0 THEN 
1533 Hw_io_error:Io_error=1
1534    END IF
1535  SUBEND
1536  !
1537 Hw_host_addr:DEF FNHw_host_addr
1538 !
1539 !      This  function is used to get the host HP-IB device address.   The
1540 !      host HP-IB device address is returned in the function result.
1541 !
1542    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1543    INTEGER Host_addr
1544    Io_error=0
1545    ON ERROR GOTO Hw_io_error
1546    STATUS Sel_code,3;Host_addr
1547    IF 0 THEN 
1548 Hw_io_error:!
1549      Io_error=1
1550      Host_addr=0
1551    END IF
1552    RETURN Host_addr MOD 32
1553  FNEND
1554  !
1555 Hw_dev_clear:SUB Hw_dev_clear(OPTIONAL Timeout_time)
1556!
1557!      This subprogram is used to  send  a  device  clear  to  the  HP-IB
1558!      module.  A device clear will abort a running ICODE program and set
1559!      the HP-IB module HP-IB interface to a reset state.  Note that this
1560!      does not dispose any HP-IB module memory blocks.
1561!
1562    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1563    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1564    ON ERROR GOTO Hw_io_error
1565    IF NPAR=1 THEN 
1566      IF Timeout_time THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1567    END IF
1568    Io_error=0
1569    CLEAR @Hpib_mod
1570    IF 0 THEN 
1571 Hw_io_error:Io_error=1
1572    END IF
1573  SUBEND
1574  !
1575 Hw_get_dev_sels:SUB Hw_get_dev_sels(INTEGER Dev_sel_list(*),INTEGER Cant_check_list(*))
1576!
1577!      This  subprogram  is  used  to  find out the device select code of
1578!      every HP3565S hardware system currently  connected  to  the  host.
1579!      All  selector  slots  (7 through 31)  are checked for HP-IB cards.
1580!      All selector slots that are found to have HP-IB cards are searched
1581!      for HP3565S hardware.   To search  a  selector  slot  for  HP3565S
1582!      hardware,  all  HP-IB  device  address  (0  through 31 except host
1583!      address) are sent ID?.   If the device responds  with  'HP35651A',
1584!      then  the  device  selector address is noted in <dev_sel_list(*)>.
1585!      The list of HP3565S hardware device selector addresses is returned
1586!      to the host in <dev_sel_list(*)>.   Note that  a  device  selector
1587!      address  of  934  can  be  broken  down into a selector of 9 and a
1588!      device address of 34.   See BASIC manual for more  information  of
1589!      device selectors.  <Cant_check_list(*)> contains information about
1590!      entire  selectors  and device selector addresses that could not be
1591!      checked.   If a HP-IB card is not an active controller,  then  the
1592!      device  addresses  on  that selector bus can not be checked.   The
1593!      selector number (7 through 31)  of any non-active HP-IB controller
1594!      is entered into <cant_check_list>.   For every HP-IB  card  found,
1595!      there is one device address that can not be checked.   That is the
1596!      address of the host on that  bus.   For  every  active  controller
1597!      HP-IB card in the host, the device selector address of the host is
1598!      placed in <cant_check_list(*)> (700->731,800->831,...,3100->3131).
1599!      Both <dev_sel_list(*)> and <cant_check_list(*)> are REDIMed to the
1600!      number  of  elements  placed  in each respective list.   If either
1601!      array is not large enough to hold the entire  list,  then  entries
1602!      are  made until the lists are full and an error is logged.   If no
1603!      HP3565S  hardware  system  is  found,  then  <dev_sel_list(*)>  is
1604!      REDIMed to one element containing one zero and an error is logged.
1605!
1606    COM /Hw_com2/ INTEGER Io_error,INTEGER Dummy1,INTEGER Dummy2
1607    INTEGER Dev_sel_size,Dev_sel_last,Cant_check_size,Cant_check_last
1608    INTEGER Sel_code,Sel_status,Hpib_addr,Host_hpib_addr,Dev_sel_code
1609    DIM Id_response$[255]
1610    !
1611    Print_hpib_addr=1
1612    !
1613    Io_error=0
1614    MAT Dev_sel_list= (0)
1615    Dev_sel_size=SIZE(Dev_sel_list,1)
1616    Dev_sel_last=0
1617    MAT Dev_sel_list= (0)
1618    Cant_check_size=SIZE(Cant_check_list,1)
1619    Cant_check_last=0
1620    !
1621    FOR Sel_code=7 TO 31
1622      ON ERROR GOTO Hw_no_sel_code
1623      STATUS Sel_code,0;Sel_status
1624      IF 0 THEN 
1625 Hw_no_sel_code:Sel_status=-1
1626      END IF
1627      IF Sel_status=1 THEN 
1628        STATUS Sel_code,3;Sel_status
1629        IF NOT BIT(Sel_status,6) THEN    !hp-ib card isn't active controller
1630          Cant_check_last=Cant_check_last+1
1631          IF Cant_check_last<=Cant_check_size THEN 
1632            Cant_check_list(Cant_check_last)=Sel_code
1633          ELSE
1634            Io_error=1
1635          END IF
1636        ELSE                               !hp-ib card is active controller
1637          Host_hpib_addr=Sel_status MOD 32 !check all addrs except host addr
1638          FOR Hpib_addr=0 TO 31
1639            Dev_sel_code=(Sel_code*100)+Hpib_addr
1640            IF Hpib_addr=Host_hpib_addr OR Hpib_addr=Print_hpib_addr THEN 
1641              Cant_check_last=Cant_check_last+1
1642              IF Cant_check_last<=Cant_check_size THEN 
1643                Cant_check_list(Cant_check_last)=Dev_sel_code
1644              ELSE
1645                Io_error=1
1646              END IF
1647            ELSE
1648              ON TIMEOUT Sel_code,.1 GOTO Hw_no_response
1649              ON ERROR GOTO Hw_no_response
1650              CLEAR Dev_sel_code
1651              OUTPUT Dev_sel_code;" "
1652              OUTPUT Dev_sel_code;"ID?"
1653              ENTER Dev_sel_code;Id_response$
1654              IF 0 THEN 
1655 Hw_no_response:Id_response$=""
1656              END IF
1657              OFF TIMEOUT Sel_code
1658              OFF ERROR 
1659              IF POS(Id_response$,"HP35651A") THEN 
1660                Dev_sel_last=Dev_sel_last+1
1661                IF Dev_sel_last<=Dev_sel_size THEN 
1662                  Dev_sel_list(Dev_sel_last)=Dev_sel_code
1663                ELSE
1664                  Io_error=1
1665                END IF
1666              END IF                ! found Interface Module
1667            END IF
1668          NEXT Hpib_addr
1669        END IF                      ! host is active controller
1670      END IF                        ! hp-ib card present
1671    NEXT Sel_code
1672    !
1673    REDIM Dev_sel_list(1:MIN(Dev_sel_size,MAX(Dev_sel_last,1)))
1674    REDIM Cant_check_list(1:MIN(Cant_check_size,MAX(Cant_check_last,1)))
1675    IF Dev_sel_list(1)=0 THEN Io_error=1
1676    !
1677  SUBEND
1678  !
1679 Hw_set_dev_sel:SUB Hw_set_dev_sel(INTEGER Dev_sel_code)
1680!
1681!      This  subprogram is used to set the current device select code for
1682!      the HP3565S hardware.   The current device select code will be set
1683!      to  <dev_sel_code>.   Until  this  subprogram  is  used to set the
1684!      current device select code, no other hardware interface subprogram
1685!      may be used.   The three exceptions to this  are  Hw_get_dev_sels,
1686!      Hw_hw,  and  Hw_io_error.   Once the current device select code is
1687!      set, no other HP3565S demo program files need worry  about  device
1688!      select  codes,  I/O  addresses, or other such nasty things.   Note
1689!      that this subprogram should be used the CNFG file ONLY.
1690!
1691    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1692    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1693    Io_error=0
1694    ON ERROR GOTO Hw_bad_ds_code
1695    Sel_code=Dev_sel_code DIV 100
1696    Hpib_addr=Dev_sel_code MOD 100
1697    ASSIGN @Hpib_mod TO Dev_sel_code
1698    ASSIGN @Bin_hpib_mod TO Dev_sel_code;FORMAT OFF
1699    IF 0 THEN 
1700 Hw_bad_ds_code:Io_error=1
1701    END IF
1702  SUBEND
1703  !
1704 Hw_cur_dev_sel:DEF FNHw_cur_dev_sel
1705!
1706!      This function is used to get the current device select code.   The
1707!      current device select code is returned  as  the  function  result.
1708!      Note  that  the  device  select  code  is set by the configuration
1709!      (CNFG) file.
1710!
1711    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1712    Io_error=0
1713    RETURN Sel_code*100+Hpib_addr
1714  FNEND
1715  !
1716 Hw_stat_2_str:DEF FNHw_stat_2_str$(Stat)
1717 !
1718 !      This function is used to convert a HP-IB  module  status  register
1719 !      value  into  a  string containing a three letter mnemonic code for
1720 !      each active status bit.   Following each mnemonic code will  be  a
1721 !      '|'.  The mnemonic codes are as follows:
1722 !
1723 !      Bit Value Bit Pos  Mnemonic        Definition
1724 !      --------- -------  --------        ---------------------------------
1725 !            1=   bit 0      RQS|         Request Control of HP-IB bus.
1726 !            2=   bit 1    - - - - - not used - - - - -
1727 !            4=   bit 2      UPP|         ICODE program paused.
1728 !            8=   bit 3      PRG|         ICODE program complete.
1729 !           16=   bit 4      RDY|         Ready for anything.
1730 !           32=   bit 5      ERR|         Error condition exists.
1731 !           64=   bit 6      RQS|         Service Request.
1732 !          128=   bit 7      MSG|         A message is ready for the host.
1733 !          256=   bit 8      FRQ|         Fast bus SRQ signal line.
1734 !          512=   bit 9      IRQ|         Fast bus IRQ signal line.
1735 !         1024=   bit10      SHT|         Fast bus SHUTDOWN signal line.
1736 !         2048=   bit11      TRG|         Fast bus TRG signal line.
1737 !         4096=   bit12    - - - - - not used - - - - -
1738 !         8091=   bit13    - - - - - not used - - - - -
1739 !        16384=   bit14      PON|         Power on.
1740 !
1741 !      The string is returned to the caller in the function result string.
1742 !      For example, FNHw_stat_2_str$(2184) would return "PRG|MSG|TRG|".
1743 !
1744    DIM A$[255]
1745    A$=""
1746    IF BIT(Stat,0) THEN 
1747      A$=A$&"RQC|"
1748    END IF
1749    IF BIT(Stat,2) THEN 
1750      A$=A$&"UPP|"
1751    END IF
1752    IF BIT(Stat,3) THEN 
1753      A$=A$&"PRG|"
1754    END IF
1755    IF BIT(Stat,4) THEN 
1756      A$=A$&"RDY|"
1757    END IF
1758    IF BIT(Stat,5) THEN 
1759      A$=A$&"ERR|"
1760    END IF
1761    IF BIT(Stat,6) THEN 
1762      A$=A$&"RQS|"
1763    END IF
1764    IF BIT(Stat,7) THEN 
1765      A$=A$&"MSG|"
1766    END IF
1767    IF BIT(Stat,8) THEN 
1768      A$=A$&"FRQ|"
1769    END IF
1770    IF BIT(Stat,9) THEN 
1771      A$=A$&"IRQ|"
1772    END IF
1773    IF BIT(Stat,10) THEN 
1774      A$=A$&"SHT|"
1775    END IF
1776    IF BIT(Stat,11) THEN 
1777      A$=A$&"TRG|"
1778    END IF
1779    IF BIT(Stat,14) THEN 
1780      A$=A$&"PON|"
1781    END IF
1782    IF A$="" THEN RETURN ""
1783    RETURN TRIM$(A$[1,LEN(A$)-1])
1784  FNEND
1785  !
1786 Hw_mainmem_aval:DEF FNHw_mainmem_aval(OPTIONAL Timeout_time)
1787 !
1788 !      This function is used to get the total amount (in words)  of HP-IB
1789 !      module main data RAM that has not been allocated.  The amount will
1790 !      be returned in the function result.   Note that the value returned
1791 !      by this function is not necessarily the size of the largest block.
1792 !      <Timeout_time> is an optional timeout parameter in  seconds.
1793 !
1794    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1795    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1796    REAL Mem_available,Dummy
1797    Io_error=0
1798    ON ERROR GOTO Hw_io_error
1799    IF NPAR=1 THEN 
1800      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1801    END IF
1802    !
1803    OUTPUT @Hpib_mod;"MEM?"
1804    ENTER @Hpib_mod;Mem_available,Dummy,Dummy,Dummy
1805    IF 0 THEN 
1806 Hw_io_error:!
1807      Io_error=1
1808      Mem_available=0
1809    END IF
1810    RETURN Mem_available
1811  FNEND
1812  !
1813 Hw_mainblk_aval:DEF FNHw_mainblk_aval(OPTIONAL Timeout_time)
1814 !
1815 !      The function is used to get the size (in  words)  of  the  largest
1816 !      HP-IB module main data RAM block.   This value will be returned as
1817 !      the  function  result.   <Timeout_time>  is  an  optional  timeout
1818 !      parameter in seconds.
1819 !
1820    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1821    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1822    REAL Mem_available,Dummy
1823    Io_error=0
1824    ON ERROR GOTO Hw_io_error
1825    IF NPAR=1 THEN 
1826      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1827    END IF
1828    OUTPUT @Hpib_mod;"MEM?"
1829    ENTER @Hpib_mod;Dummy,Mem_available,Dummy,Dummy
1830    IF 0 THEN 
1831 Hw_io_error:!
1832      Io_error=1
1833      Mem_available=0
1834    END IF
1835    RETURN Mem_available
1836  FNEND
1837  !
1838 Hw_spmem_aval:DEF FNHw_spmem_aval(OPTIONAL Timeout_time)
1839 !
1840 !      This function is used to get the total amount (in words)  of HP-IB
1841 !      module  SP data RAM that has not been allocated.   The amount will
1842 !      be returned in the function result.   Note that the value returned
1843 !      by this function is not necessarily the size of the largest block.
1844 !      <Timeout_time>  is an optional timeout parameter in seconds.
1845 !
1846    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1847    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1848    REAL Mem_available,Dummy
1849    Io_error=0
1850    ON ERROR GOTO Hw_io_error
1851    IF NPAR=1 THEN 
1852      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1853    END IF
1854    OUTPUT @Hpib_mod;"MEM?"
1855    ENTER @Hpib_mod;Dummy,Dummy,Mem_available,Dummy
1856    IF 0 THEN 
1857 Hw_io_error:!
1858      Io_error=1
1859      Mem_available=0
1860    END IF
1861    RETURN Mem_available
1862  FNEND
1863  !
1864 Hw_spblk_aval:DEF FNHw_spblk_aval(OPTIONAL Timeout_time)
1865 !
1866 !      The function is used to get the size (in  words)  if  the  largest
1867 !      HP-IB  module  SP data RAM block.   This value will be returned as
1868 !      the  function  result.   <Timeout_time>  is  an  optional  timeout
1869 !      parameter in seconds.
1870 !
1871    COM /Hw_com1/ @Hpib_mod,@Bin_hpib_mod
1872    COM /Hw_com2/ INTEGER Io_error,INTEGER Sel_code,INTEGER Hpib_addr
1873    REAL Mem_available,Dummy
1874    Io_error=0
1875    ON ERROR GOTO Hw_io_error
1876    IF NPAR=1 THEN 
1877      IF Timeout_time>0 THEN ON TIMEOUT Sel_code,Timeout_time GOTO Hw_io_error
1878    END IF
1879    OUTPUT @Hpib_mod;"MEM?"
1880    ENTER @Hpib_mod;Dummy,Dummy,Dummy,Mem_available
1881    IF 0 THEN 
1882 Hw_io_error:Io_error=1
1883      Mem_available=0
1884    END IF
1885    RETURN Mem_available
1886  FNEND
1887  !
1888 Hw_get_errstr:DEF FNHw_get_errstr$(Error_num)
1889 !
1890 !      This function is used to convert an HP-IB module error number into
1891 !      the appropriate error message string.   The error number (or error
1892 !      code) is passed to this function in <Error_num>.   The appropriate
1893 !      error  message  string  is  returned to the caller in the function
1894 !      result string.   If an invalid error number is passed in  to  this
1895 !      function, then VAL$(Error_num)  is returned to the caller.
1896 !
1897    DIM Msg$[100]
1898    INTEGER Current_err
1899    ON ERROR GOTO Hw_not_found
1900    REPEAT
1901      READ Current_err,Msg$
1902    UNTIL Current_err=Error_num
1903    OFF ERROR 
1904    RETURN Msg$
1905    STOP
1906 Hw_not_found:OFF ERROR 
1907    RETURN VAL$(Error_num)
1908    STOP
1909    DATA -100,"Command error (unknown command)"
1910    DATA -101,"Invalid character received"
1911    DATA -110,"Command Header error"
1912    DATA -111,"Header delimiter error"
1913    DATA -120,"Numeric argument error"
1914    DATA -121,"Wrong Data Type (numeric expected)"
1915    DATA -122,"Precision error; rounding occurred"
1916    DATA -123,"Numeric overflow"
1917    DATA -129,"Missing numeric argument"
1918    DATA -130,"non numeric argument error (char, string or block)"
1919    DATA -131,"Wrong Data Type (char expected)"
1920    DATA -132,"Wrong Data Type (string expected)"
1921    DATA -133,"Wrong Data Type (block type #A required)"
1922    DATA -134,"Data Overflow: string or block too long"
1923    DATA -139,"Missing non numeric argument"
1924    DATA -141,"Command Buffer Overflow"
1925    DATA -142,"Too many arguments"
1926    DATA -143,"Argument delimiter error"
1927    DATA -144,"Invalid message unit delimiter"
1928    DATA -200,"No Can Do (generic execution error)"
1929    DATA -201,"Not executable in local mode"
1930    DATA -202,"Settings lost due to  rtl  or  pon "
1931    DATA -203,"Trigger ignored"
1932    DATA -211,"Legal command, but settings conflict"
1933    DATA -212,"Argument out of range"
1934    DATA -221,"Busy doing something else"
1935    DATA -222,"Insufficient capability or configuration"
1936    DATA -231,"Input buffer full or overflow"
1937    DATA -232,"Output buffer full or overflow"
1938    DATA -1,"unexpected interrupt"
1939    DATA -2,"stack overflow"
1940    DATA -3,"reference to NIL pointer"
1941    DATA -4,"integer overflow"
1942    DATA -5,"divide by zero"
1943    DATA -6,"real math overflow"
1944    DATA -7,"real math underflow"
1945    DATA -8,"value range error"
1946    DATA -9,"case value range error"
1947    DATA -10,"Bad input format or String subscript out of range"
1948    DATA -11,"CPU word access to odd address"
1949    DATA -12,"CPU bus error"
1950    DATA -13,"illegal CPU instruction"
1951    DATA -14,"CPU privilege violation"
1952    DATA -15,"bad argument  SIN/COS"
1953    DATA -16,"bad argument  LN"
1954    DATA -17,"bad argument  SQRT"
1955    DATA -18,"bad argument  real/BCD conversion"
1956    DATA -19,"bad argument  BCD/real conversion"
1957    DATA -20,"stopped by user"
1958    DATA -21,"unassigned CPU trap"
1959    DATA -25,"undefined macro parameter"
1960    DATA -26,"I/O routine error"
1961    DATA -28,"CPU trace exception"
1962    DATA 101,"unable to allocate block. ( see NEW and SNEW )"
1963    DATA 102,"Undefined blockid."
1964    DATA 103,"Block will not hold all the data."
1965    DATA 104,"Output string buffer overflow."
1966    DATA 105,"Output request buffer overflow."
1967    DATA 200,"FP-IB bus is reset, unable to take control. (see TCF)"
1968    DATA 201,"Other FP-IB controller present. (see TCF)"
1969    DATA 202,"FP-IB read transfer timeout."
1970    DATA 203,"FP-IB write transfer timeout."
1971    DATA 204,"FP-IB read overflow."
1972    DATA 205,"Interface FP-IB address used."
1973    DATA 206,"Interface module not in control of FP-IB."
1974    DATA 207,"I/O aborted because the FP-IB module is not responding."
1975    DATA 208,"SYNC timeout error."
1976    DATA 209,"FP-IB went into an unexpected reset state."
1977    DATA 210,"Trigger sequence timeout error.(Someone is asserting trig line)"
1978    DATA 300,"An ICODE program is not running."
1979    DATA 301,"An ICODE program cannot be continued because it is not paused."
1980    DATA 302,"Command cannot be completed because an ICODE program is active."
1981    DATA 303,"Attempt to fetch past the end of an ICODE block has occurred."
1982    DATA 304,"Non-existent icode variable fetch."
1983    DATA 305,"Illegal blockid use."
1984    DATA 306,"ICODE value range error."
1985    DATA 307,"Block offset too large for block."
1986    DATA 308,"Branch out of bounds."
1987    DATA 309,"Access past block boundaries."
1988    DATA 310,"Subroutines nested more than 16."
1989    DATA 311,"An RTS instruction has been executed without an active sub."
1990    DATA 312,"f_thruput executed before a f_ready_ram or f_ready_disc."
1991    DATA 313,"Illegal block size"
1992    DATA 314,"Block exponent offset is out of header block."
1993    DATA 315,"Block exponent overflow."
1994    DATA 316,"Block exponent underflow."
1995    DATA 317,"No header block allocated for block exponent."
1996    DATA 318,"Requested window size is odd."
1997    DATA 319,"Illegal relationship between f_sample args."
1998    DATA 320,"Illegal opcode."
1999    DATA 321,"Work block not declared."
2000    DATA 322,"Work block is too small."
2001    DATA 323,"Fast average exponent out of range."
2002    DATA 324,"Missing mf_mod from f_ready_ram/f_ready_disc mf_mod list."
2003    DATA 325,"f_ready_ram/f_ready_disc mf_mod list block too small."
2004    DATA 326,"f_ready_disc disc segment block too small."
2005    DATA 327,"disc address not on block boundary."
2006    DATA 328,"f_keep_ready_ram with out f_ready_ram."
2007    DATA 401,"HP-IB deadlock."
2008    DATA 402,"The interface module is not in control of the HP-IB."
2009    DATA 403,"The interface module is not addressed to listen."
2010    DATA 404,"The interface module is not addressed to talk."
2011    DATA 405,"HP-IB timeout."
2012    DATA 406,"Disc Error reported."
2013    DATA 407,"Disc reports no device present."
2014    DATA 408,"Disc blocksize too large ( > 1024 )"
2015    DATA 409,"Disc reports bad mode."
2016    DATA 410,"Disc reports no such block."
2017    DATA 411,"The disc is uninitialized."
2018    DATA 412,"Disc initialization failed."
2019    DATA 413,"The disc is not ready."
2020    DATA 414,"The disc is write protected."
2021    DATA 415,"Disc reports no such block."
2022    DATA 416,"Disc reported a bad block."
2023    DATA 417,"The disc medium was changed during transfer."
2024    DATA 418,"A icode transfer of this type has not been set up. (RBLK,WBLK)"
2025    DATA 419,"HP-IB transfer not completed. (Usually to the host)"
2026    DATA 420,"Disc message length error."
2027    DATA 500,"undefined, reserved"
2028    DATA 501,"unexpected interrupt during power on tests"
2029    DATA 502,"interrupt test generation failure"
2030    DATA 503,"tms320 failure"
2031    DATA 504,"timer failure"
2032    DATA 505,"dma_failure"
2033    DATA 506,"fpib failure"
2034    DATA 507,"hpib failure"
2035    DATA 508,"undefined, reserved"
2036    DATA 509,"high byte rom checksum error"
2037    DATA 510,"low byte rom checksum error"
2038    DATA 511,"signal processor program  ram failure"
2039    DATA 512,"signal processor data ram failure"
2040    DATA 513,"ram refresh failure"
2041    DATA 514,"ram error (non refresh error)"
2042    DATA 515,"not enough ram"
2043    DATA 523,"io dtack failure ( ie leds )"
2044    DATA 524,"timer chip dtack failure"
2045    DATA 525,"dma dtack failure"
2046    DATA 526,"fpib dtack failure"
2047    DATA 527,"hpib dtack failure"
2048    DATA 528,"sp program ram dtack failure"
2049    DATA 529,"sp data ram dtack failure"
2050    DATA 530,"main ram dtack failure"
2051    DATA 540,"main ram test failure"
2052    DATA 541,"fpib test failure"
2053    DATA 542,"sp ram failure"
2054    DATA 543,"sp random number generator failure"
2055    DATA 544,"sp USM chip failure"
2056    DATA 545,"novram checksum error"
2057    DATA 546,"sp not responding"
2058    DATA 547,"sp interrupt routine not responding"
2059    DATA 548,"dma chip is inactive"
2060    DATA 549,"bus error during dma operation"
2061    DATA 550,"generic sp failure."
2062    DATA 600,"bit 0 of main ram bad."
2063    DATA 601,"bit 1 of main ram bad."
2064    DATA 602,"bit 2 of main ram bad."
2065    DATA 603,"bit 3 of main ram bad."
2066    DATA 604,"bit 4 of main ram bad."
2067    DATA 605,"bit 5 of main ram bad."
2068    DATA 606,"bit 6 of main ram bad."
2069    DATA 607,"bit 7 of main ram bad."
2070    DATA 608,"bit 8 of main ram bad."
2071    DATA 609,"bit 9 of main ram bad."
2072    DATA 610,"bit 10 of main ram bad."
2073    DATA 611,"bit 11 of main ram bad."
2074    DATA 612,"bit 12 of main ram bad."
2075    DATA 613,"bit 13 of main ram bad."
2076    DATA 614,"bit 14 of main ram bad."
2077    DATA 615,"bit 15 of main ram bad."
2078    DATA 700,"bit 0 of signal processor data ram bad."
2079    DATA 701,"bit 1 of signal processor data ram bad."
2080    DATA 702,"bit 2 of signal processor data ram bad."
2081    DATA 703,"bit 3 of signal processor data ram bad."
2082    DATA 704,"bit 4 of signal processor data ram bad."
2083    DATA 705,"bit 5 of signal processor data ram bad."
2084    DATA 706,"bit 6 of signal processor data ram bad."
2085    DATA 707,"bit 7 of signal processor data ram bad."
2086    DATA 708,"bit 8 of signal processor data ram bad."
2087    DATA 709,"bit 9 of signal processor data ram bad."
2088    DATA 710,"bit 10 of signal processor data ram bad."
2089    DATA 711,"bit 11 of signal processor data ram bad."
2090    DATA 712,"bit 12 of signal processor data ram bad."
2091    DATA 713,"bit 13 of signal processor data ram bad."
2092    DATA 714,"bit 14 of signal processor data ram bad."
2093    DATA 715,"bit 15 of signal processor data ram bad."
2094    DATA 800,"bit 0 of signal processor prog ram bad."
2095    DATA 801,"bit 1 of signal processor prog ram bad."
2096    DATA 802,"bit 2 of signal processor prog ram bad."
2097    DATA 803,"bit 3 of signal processor prog ram bad."
2098    DATA 804,"bit 4 of signal processor prog ram bad."
2099    DATA 805,"bit 5 of signal processor prog ram bad."
2100    DATA 806,"bit 6 of signal processor prog ram bad."
2101    DATA 807,"bit 7 of signal processor prog ram bad."
2102    DATA 808,"bit 8 of signal processor prog ram bad."
2103    DATA 809,"bit 9 of signal processor prog ram bad."
2104    DATA 810,"bit 10 of signal processor prog ram bad."
2105    DATA 811,"bit 11 of signal processor prog ram bad."
2106    DATA 812,"bit 12 of signal processor prog ram bad."
2107    DATA 813,"bit 13 of signal processor prog ram bad."
2108    DATA 814,"bit 14 of signal processor prog ram bad."
2109    DATA 815,"bit 15 of signal processor prog ram bad."
2110  FNEND
2111  !
2112  ! PAGE ->
2113  !***************************************************************
2114 Hw_str_2_stat:DEF FNHw_str_2_stat(A$)
2115 !
2116 !      This function is used to convert a string with HP-IB module status
2117 !      bit  mnemonic  codes  into  an  numerical  value representing that
2118 !      status string.  Each mnemonic string can be delimited by a ','  or
2119 !      '|'.  The list of valid mnemonic strings is as follows:
2120 !
2121 !      Bit Value Bit Pos  Mnemonic
2122 !      --------- -------  ---------------------------------------
2123 !            1=   bit 0      RQS    or    REQUEST CONTROL
2124 !            2=   bit 1      BIT1
2125 !            4=   bit 2      UPP    or    PAUSE
2126 !            8=   bit 3      PRG    or    STOPPED
2127 !           16=   bit 4      RDY    or    READY
2128 !           32=   bit 5      ERR    or    ERROR
2129 !           64=   bit 6      RQS
2130 !          128=   bit 7      MSG    or    MESSAGE
2131 !          256=   bit 8      FRQ    or    FAST BUS SRQ
2132 !          512=   bit 9      IRQ
2133 !         1024=   bit10      SHT    or    SHUT     or    SHUTDOWN
2134 !         2048=   bit11      TRG    or    TRIG     or    TRIGGER
2135 !         4096=   bit12      BIT12
2136 !         8091=   bit13      BIT13
2137 !        16384=   bit14      PON    or    POWER ON
2138 !
2139 !      The  numerical  value  calculated will be returned in the function
2140 !      result.  For example,  FNHw_str_2_stat("PAUSE|RQS,FAST  BUS  SRQ")
2141 !      would return 324 as a result.   If any field of Hp_ib_stat_str$ is
2142 !      not recognized by this function, then an error is  logged  on  the
2143 !      CRT and no value returned. This is the inverse of FNHw_stat_2_str$
2144 !      which converts the numerical value into a status string containing
2145 !      a mnemonic entry for each active status bit.
2146 !
2147    ALLOCATE Temp$[255],Bit$[40]
2148    Temp$=TRIM$(UPC$(A$))
2149    Stat=0
2150    WHILE POS(Temp$,",")
2151      Temp$[POS(Temp$,",");1]="|"
2152    END WHILE
2153    WHILE POS(Temp$,"|")
2154      Bit$=Temp$[1,POS(Temp$,"|")-1]
2155      GOSUB Hw_add_bit_val
2156      Temp$=Temp$[POS(Temp$,"|")+1]
2157    END WHILE
2158    IF Temp$<>"" THEN 
2159      Bit$=Temp$
2160      GOSUB Hw_add_bit_val
2161    END IF
2162    RETURN Stat
2163 Hw_add_bit_val: !
2164    SELECT TRIM$(Bit$)
2165    CASE "RQC","REQUEST CONTROL"
2166      Stat=Stat+1        !bit 0
2167    CASE "BIT1"
2168      Stat=Stat+2
2169    CASE "UPP","PAUSE"
2170      Stat=Stat+4        !bit 2
2171    CASE "PRG","STOPPED"
2172      Stat=Stat+8        !bit 3
2173    CASE "RDY","READY"
2174      Stat=Stat+16       !bit 4
2175    CASE "ERR","ERROR"
2176      Stat=Stat+32       !bit 5
2177    CASE "RQS"
2178      Stat=Stat+64       !bit 6
2179    CASE "MSG","MESSAGE"
2180      Stat=Stat+128      !bit 7
2181    CASE "FRQ","FAST BUS SRQ"
2182      Stat=Stat+256      !bit 8
2183    CASE "IRQ"
2184      Stat=Stat+512      !bit 9
2185    CASE "SHT","SHUT","SHUTDOWN"
2186      Stat=Stat+1024     !bit 10
2187    CASE "TRG","TRIG","TRIGGER"
2188      Stat=Stat+2048     !bit 11
2189    CASE "BIT12"
2190      Stat=Stat+4096     !bit 12
2191    CASE "BIT13"
2192      Stat=Stat+8192     !bit 13
2193    CASE "PON","POWER ON"
2194      Stat=Stat+16384    !bit 14
2195    CASE ELSE
2196      User_error("*** Couldn't recognize "&Bit$&" in FNHw_str_2_stat***")
2197    END SELECT
2198    RETURN 
2199  FNEND
2200  !
2201  ! PAGE ->
2202  !****************************************************************
2203 Icode_icode:SUB Icode_icode
2204  !
2205  !  This subroutine is used to initialize the ICODE file. As you can see
2206  !  there is not much to initialize.
2207  !
2208  SUBEND
2209  !
2210 Icode_assemble:DEF FNIcode_assemble(Source$(*),INTEGER Object(*),INTEGER Info_info,Info$(*),INTEGER Enable_list_arg,List$(*))
2211!
2212!
2213!   This subprogram 'Icode_assemble', is used to translate ICODE assembly
2214!   language programs into object code that can be run in the HP3565S HP-IB
2215!   module. The ICODE assembly language is defined in the ICODE section of
2216!   demo programs manual.
2217!
2218!   ==> Assembler activation:
2219!
2220!   Error_count=FNIcode_assemble(Source$(*),INTEGER Object(*)
2221!               INTEGER Info_info,Info$(*),INTEGER Enable_list_arg
2222!               List$(*))
2223!
2224!   Source$(*):     Input  - Holds ICODE source code.  Each line of Source$
2225!                            contains one line of source code.  Instructions
2226!                            with large parameter list may use more than one
2227!                            line by using a continuation line. The first
2228!                            character of a continuation line must be a '.'.
2229!                            The Source$ index must start at 0.
2230!                            The length the string elements in Source$ is
2231!                            defined by the user.
2232!                            Assembly will start at the beginning of Source$
2233!                            and continue until the end of Source$ is found,
2234!                            or until a line containing 'EL_COMPLETO' is
2235!                            found.  If 'EL_COMPLETO' is used to terminate
2236!                            assembly, then Source$ is REDIMed to the actual
2237!                            size of the source program.
2238!   Object(*):      Output - Holds assembled ICODE object code.
2239!                            The Object index must start at 0.
2240!                            Object(*) is REDIMed to the size of the object
2241!                            code.
2242!                            Note that Info_info=2 will increase the size
2243!                            object array by 1 element for each assembled
2244!                            instruction.
2245!   Info_info:      Input  - Determines what information the assembler
2246!                            should put in the Info$(*) array.
2247!                            0 - Info$(*) is not accessed.
2248!                            1 - Info$(*) is filled with information
2249!                                to be used by 'Icode_dld', 'Icode_ext_id'
2250!                                and 'Icode_def_ext'.
2251!                            2 - Info$(*) is filled with information as
2252!                                if Info_info=1, and filled with info
2253!                                to be used by the 'Icode_debug'.
2254!                                Info_info=2 will also cause 'c_nop's to
2255!                                be insert in between each instruction.
2256!                                This is used by the debugger to set break
2257!                                points. Note that this will increase the
2258!                                size of the object code and also the size
2259!                                of the listing output if enabled.
2260!                                This mode may be used during program
2261!                                development.
2262!   Info$(*):       Output - Holds information to be used by other ICODE
2263!                            file subprograms.
2264!                            The Info$ index must start at 0.
2265!                            If Info_info=0, then Info$(*) is unaffected.
2266!                            If Info_info<>0 then Info$(*) string elements
2267!                            must be 40 characters long.
2268!                            If Info_info=1 then Info$(*) must have 6 lines
2269!                            + one line for each DEFBLK_SP,DEFBLK_MAIN or
2270!                            DEFBLK_EXT.
2271!                            If Info_info=2 then Info$(*) must have as many
2272!                            lines as in Info_info=1 + 4 + one line for each
2273!                            DEFBLK_VAR, DEFBLK_CON, VAR, + one line for
2274!                            each label, + one line for each 10 instructions.
2275!   Enable_list_arg: Input - If 0, then List$(*) will not be accessed.
2276!                            If 1, then List$(*) will be filled with the
2277!                                  assembly listing.
2278!   List$(*):       Output - Holds the assembly listing.
2279!                            The number of elements and the length of each
2280!                            string in List$ is defined by the user.
2281!                            The List$ index must start at 0.
2282!                            List$ string elements should be 15 chars
2283!                            longer than the string elements in Source(*).
2284!                            The number of elements in List$ should be
2285!                            ABOUT 2 to 4 times the number of lines in
2286!                            Source$(*). Note that Info_info=2 will cause
2287!                            the assembler to insert 'c_nop's in between
2288!                            each instruction.  These 'c_nop's will show
2289!                            up in List$. List$ will be REDIMed to the size
2290!                            required to host the assembly listing
2291!
2292!   ==> Example assembler activation:
2293!
2294!   The following is an example of how the assemble an in line ICODE program.
2295!
2296!   110 Icode_program:!
2297!   120 DATA "              err_abrt_count  5"
2298!   130 DATA "              err_disp_lines  3"
2299!   140 DATA "              var             loop_ptr    0                "
2300!   150 DATA "              const           loop_max   10 ! loop 10 times"
2301!   160 DATA "                                                           "
2302!   170 DATA "loop_begin:   f_signal        loop_ptr
2303!   180 DATA "              v_add           loop_ptr,loop_ptr,1 ! inc ptr"
2304!   190 DATA "              c_beq           loop_begin loop_ptr          "
2305!   200 DATA ".                             loop_max                     "
2306!   210 DATA "              c_end                                        "
2307!   220 DATA "el_completo"
2308!    .
2309!    .
2310!   500 DIM Source$(0:200)[80],List$(0:400)[120],Source_line$[80]
2311!   510 INTEGER Object(0:300),Info_info,Enable_list,Prog_id,Error_count
2312!    .
2313!   600 Source_ptr=-1
2314!   610 RESTORE Icode_program
2315!   620 REPEAT
2316!   630   READ Source_line$
2317!   640   Source_ptr=source_ptr+1
2318!   650   Source$(Source_ptr)=Source_line$
2319!   660 UNTIL Source_line="el_completo"
2320!   670 !
2321!   680 Info_info=2              ! Enable auto allocate vars and debugger
2322!   690 Enable_list=1            ! Enable listing
2323!   700 !
2324!   710 Error_count=FNIcode_assemble(Source$(*),Object(*),Info_info,Info$(*)
2325!                                    Enable_list,List$(*))
2326!   720 IF Error_count<>0 THEN
2327!   730   OUTPUT CRT; "Errors during assembly.  Program paused"
2328!   740   PAUSE
2329!   750 END IF
2330!   760 Prog_id=FNIcode_dld(Object(*),Info_info,Info$(*))  ! download prog
2331!   770 IF Prog_id<=0 THEN
2332!   780   OUTPUT CRT; "Couldn't download ICODE program. Program paused."
2333!   790   PAUSE
2334!   800 END IF
2335!   810 FNHw_cmd("PROG "&Prog_id)       ! start ICODE program
2336!    .
2337!    .
2338!
2339!   ==> Listing format: (all values in Hex)
2340!
2341!    OBJ ASM  ASM                 SOURCE CODE
2342!   ADDR VALU VALU
2343!
2344!   0004 0000 0004                var         loop_ptr   0
2345!        000A                     const       loop_max  10   ! loop 10 times
2346!
2347!   0006 003D                    <c_nop>
2348!   0007 0012,FFFE loop_begin:    f_signal    loop_ptr       ! send loop ptr
2349!   0009 003D                    <c_nop>
2350!   000A 0047,FFFE                v_add       loop_ptr,loop_ptr,1 ! inc ptr
2351!   000C FFFE,0001
2352!   000E 003D                    <c_nop>
2353!   000F 0039,0000                c_beq       loop_begin loop_ptr
2354!   0011 0006,FFFE .                          loop_max
2355!   0013 000A
2356!   0014 003D                    <c_nop>
2357!   0015 0030                     c_end
2358!   0016 003D                    <c_nop>
2359!
2360!   The array List$ will be filled the the assembly listing if the input
2361!   parameter List_enable is non zero.  The listing has the following format:
2362!       + The first column of the listing indicates the hex address into the
2363!         object array.
2364!       + The second and third columns are the data values inserted into the
2365!         Object array.
2366!       + The rest of the line is the source code
2367!       + Lines that contain <c_nop> are inserted by the assembler for use by
2368!         the debugger in setting break points. These <c_nop>s would not be  e
2369!         if Info_info were equal to 0 or 1.
2370!
2371!   ==> Source code format general:
2372!
2373!   The source code passed to the assembler through Source$(*) has two
2374!   sections. The first section is the pseudo-op   section, and the second
2375!   section is the main assembly section. Most of the syntax is  similar
2376!   to that of a standard assembler. Some global notes follow:
2377!       + All parameter fields that require a numerical field may be in
2378!         decimal or in hex. Hex numbers are specified by a "$" directly
2379!         before the hex number.
2380!       + All characters after the first occurrence of an '!' on any line
2381!         will be treated as comments.
2382!       + Parameter list elements may be delimited by either a space or by
2383!         a comma.  Between the opcode and the parameter list must be a
2384!         space.
2385!       + This is a one pass assembler.  Labels are the only type of symbol
2386!         that may be referenced before the symbol is defined.
2387!       + Once a CONST has been defined, the CONST symbol may be used any
2388!         place a numerical field is used.
2389!       + All symbols may be up to 16 characters long and are case
2390!         insensitive.  The first character in a symbol must be a letter.
2391!         The rest should be letters, numbers or an underscore.  Other
2392!         characters may not generate an error. User beware.
2393!       + Symbols may be larger than 16 characters but only the first 16
2394!         are significant.  It would be best to make sure that all symbols
2395!         are <= 16 characters in length.
2396!       + ***** NOTE: When a new symbol is defined (Variable name,   *****
2397!         *****       Block name, etc ), NO checking is done to make *****
2398!         *****       sure that the symbol is not already defined.   *****
2399!         *****       When a reference is made to a duplicate symbol,*****
2400!         *****       it is undefined as to which one will be        *****
2401!         *****       referenced.                                    *****
2402!       + Below is a list of characters with special meaning.
2403!           - '$'  used to indicate a hex number.
2404!           - '^'  used to reference a header block.
2405!           - '@'  used to reference a variable through indirection.
2406!           - ':'  used as a label terminator.
2407!           - '''  used to delimit a string parameter.
2408!           - '!'  used to indicate the beginning of a comment.
2409!           - ','  used to delimit two parameters.
2410!           - '.'  used to indicate a continuation line.
2411!
2412!
2413!   ==> Pseudo-op section:
2414!
2415!   The pseudo-op   section of a program begins at the beginning of Source(*)
2416!   and continues until the end-of-program is found or until the first main
2417!   assembly instruction is found. Below is a description of each pseudo-op
2418!   pseudo-op.
2419!
2420!
2421!      ERR_ABRT_COUNT          <error count>
2422!
2423!      This pseudo-op is used to tell the assembler how many errors should
2424!      cause the assembler to stop assembling.  By default, this value is
2425!      four.
2426!
2427!      ERR_DISP_LINES          <# lines to disp before error>
2428!
2429!      This pseudo-op is used to tell the assembler how many source lines
2430!      before an instruction with an error should be displayed on the CRT.
2431!      By default, this value is two.
2432!
2433!      VAR                     <variable_name> <init value>
2434!
2435!      This pseudo-op is used to define and initialize an ICODE variable.
2436!      The <init value> field may be a CONST only if the constant has
2437!      already been defined. To initialize one variable to the variable
2438!      number of another variable (which must already be defined) do as
2439!      follows:
2440!
2441!          20 DATA "                var        first_var      100       "
2442!          30 DATA "                var        second_var     @first_var"
2443!
2444!      In the above example, if 'first_var' is variable number 5, then
2445!      'second_var' will be initialized to 5.  Note that 'first_var' must
2446!      be defined before it may be used to initialize another variable.
2447!      This may be useful if indirect variable accesses are being used.
2448!
2449!
2450!      CONST                   <const name>     <const value>
2451!
2452!      This pseudo-op is used to define a constant.  A constant symbol may
2453!      be used any place an immediate parameter (floating point or integer)
2454!      can be used once the CONST has been defined.  If the constant is
2455!      given a floating point value, and is used is a place that requires
2456!      an integer (most of the time), the value used is INT(const_val).
2457!      i.e. the floating point number is truncated.
2458!
2459!      DEFBLK_CON              <block_name>    <block_id>
2460!
2461!      This pseudo-op is used to define a block id if the block id is known
2462!      at assembly time.
2463!
2464!      DEFBLK_VAR              <block_name>    <block_id_var_init_value>
2465!
2466!      This pseudo-op is used to define a block id where the block id will be
2467!      put in a variable.  An init value must be specified even though the
2468!      variable need not contain the actual block id until runtime.
2469!
2470!      DEFBLK_EXT              <block_name>
2471!
2472!      This pseudo-op is used to define a block name symbol within the ICODE
2473!      program, but let the actual binding of the block name to the block id
2474!      be done external to the assembly process.  To bind a block id to the
2475!      block symbol, the function 'FNIcode_def_ext' need be used.  This may
2476!      be useful if the block type (MAIN or SP) or size is not known at
2477!      assembly time.  This is also useful if multiple ICODE programs wish
2478!      to share the same block.  Through the used of 'FNIcode_def_ext', the
2479!      user may allocate their own block and then bind it to <block_name> or
2480!      tell 'FNIcode_def_ext' the block type and size, and have 'FNIcode_dld'
2481!      allocate the block at runtime.  To access the header block that may be
2482!      associated with <block_name> a 'hat' may be placed in from of the
2483!      <block_name> in the ICODE program.  i.e.   ^fft_blk_name
2484!
2485!      DEFBLK_SP               <block_name>    <blk_size> <hblk_size>
2486!
2487!      This pseudo-op is used to define an HP-IB module SP data RAM block
2488!     for the assembly process and have the downloader allocate the block
2489!     at runtime.  For assembly, only the block size and the header block
2490!     size need be known.  'FNIcode_dld'  will allocate and bind the correct
2491!     block id to <block_name>.  To access the header block that may be
2492!     associated with <block_name> a 'hat' may be placed in from of the
2493!     <block_name> in the ICODE program.  i.e.   ^fft_blk_name
2494!
2495!      DEFBLK_MAIN             <block_name>    <blk_size> <hblk_size>
2496!
2497!      This pseudo-op is used to define an HP-IB module MAIN data RAM block
2498!     for the assembly process and have the downloader allocate the block
2499!     at runtime.  For assembly, only the block size and the header block
2500!     size need be known.  'FNIcode_dld'  will allocate and bind the correct
2501!     block id to <block_name>.  To access the header block that may be
2502!     associated with <block_name> a 'hat' may be placed in front of the
2503!     <block_name> in the ICODE program.  i.e.   ^fft_blk_name
2504!
2505!      LBL_TBL_SIZE            <label_table_size>
2506!
2507!      This pseudo-op is used to define the size of the label table size.
2508!      When the assembler comes across a label definition, its name and
2509!      location are placed in this table.  Therefore, the label table must
2510!      have one entry for each label in the ICODE program.  By default,
2511!      the label table has 50 entries.
2512!
2513!      FORLBL_TBL_SIZE         <forward_label_table_size>
2514!
2515!      This pseudo-op is used to define the size of the forward reference
2516!      label table. When the assembler comes across a label reference to
2517!      a label that has not been defined yet, an entry is made in this
2518!      table.  Note that there may be more than one entry for a single
2519!      label definition.  When the label is defined, entry(s) referring
2520!      to the defined label are removed. Since the size of this table
2521!      is not a function of the number of labels, but rather the number
2522!      of undefined forward references outstanding at one time, it is
2523!      a little harder to choose the correct table size.  By default, the
2524!      forward reference label table has 100 entries.
2525!
2526!   ==> Main assembly section:
2527!
2528!      This is the section of the ICODE program that contain the executable
2529!      instructions defined in the HP3565S ICODE manual.  The syntax is
2530!      similar to that of a 'normal' assembler.  Some general rules are as
2531!      follows:
2532!           + Each instruction must begin on a new line. Instructions with
2533!             parameter lists that require more than one line may use
2534!             continuation lines.  A continuation line must have a '.' as
2535!             the first character on that line.  Continuation across symbol
2536!             boundaries is not allowed.
2537!           + Too define a label, the label must be the first symbol on the
2538!             line.  The label is terminated with an ':'.  More than one
2539!             label may be used to point to one place in the ICODE program,
2540!             but each label must be on a separate line.
2541!           + Between the opcode and the parameter list must be a space.
2542!             No comma.
2543!           + Between the parameter list elements may be commas or spaces.
2544!           + Below is some example ICODE source code. This code is NOT
2545!             meant to mean anything program wise.  It is meant to show
2546!             some of the basic constructs used in ICODE instructions.
2547!
2548! 210 DATA "label1:      f_signal first_variable   ! this is a comment "
2549! 220 DATA "             f_sync                                        "
2550! 230 DATA "label2:                  ! label2 and label3 are equivalent"
2551! 240 DATA "label3:      v_add    loop_ptr loop_ptr 1                  "
2552! 250 DATA "             c_beq    exit_prog,loop_ptr,10                "
2553! 260 DATA "             v_mult   loop_index   ! "
2554! 270 DATA ".                     loop_ptr 10 !this is a continuation line"
2555! 370 DATA "             c_goto   label1                               "
2556!
2557!           + The HP3565S ICODE documentation says that a string parameter
2558!             is preceeded by the length of the string.  To specify a string
2559!             parameter, the string need only be enclosed in single quotes
2560!             '''. The assembler will deal with the length field.
2561!           + If it is desired to enter immediate data into the ICODE
2562!             program, then the ASM_OFF directive may be used. The ASM_OFF
2563!             directive is of the form:
2564!
2565!             ASM_OFF   <parm_count> <parm1>,...,<parmn>
2566!
2567!             <parm_count> is used to specify how many parameters follow.
2568!             Each parameter is evaluated (immediate, variable, or const)
2569!             and placed in the object array.  The ASM_OFF directive may
2570!             not be embedded in another instructions parameter list.
2571!
2572 Icode_asm_start:!
2573    DIM Line$[255],Opcode$[20],Label$[20],Disp_line$[100],Version$[10]
2574    DIM Arg$[20],Variable$[20],Inst_info$[255]
2575    INTEGER Asm_loop_done,Def_loop_done,Line_ptr,I,J,K,Enable_list
2576    REAL Real_temp,Arg,Max_32_int,Min_32_int,Max_16_int,Min_16_int
2577    INTEGER Int_temp,Int_hi,Int_lo,Add_object
2578    INTEGER Source_last,Object_last
2579    INTEGER Old_forlbl_last
2580    INTEGER Info_inst_base,Info_inst_cnt,Inst_cnt
2581    DIM Error_string$[100],Block_name$[20]
2582    DIM Repeat_str$[512]
2583    !
2584    !      Let's do some initialization
2585    !
2586 Icode_version:!
2587    Version$="1.0"
2588    Disp_line$="ICODE Assembler version "&Version$&"  "
2589    DISP Disp_line$;"  Initializing."
2590    !
2591    Source_size=SIZE(Source$,1)
2592    Object_size=SIZE(Object,1)
2593    Info_size=SIZE(Info$,1)
2594    List_size=SIZE(List$,1)
2595    !
2596    Lbl_tbl_size=50            ! default label table size
2597    Forlbl_tbl_size=100        ! default forward reference label tbl size
2598    Err_abrt_count=4           ! default error count to abort assembly
2599    Err_disp_lines=2           ! default # lines to disp when error is found
2600    !
2601    Error_count=0
2602    Missing_arg=0
2603    !
2604    ! Init table pointers.   Pointers point to last entry used.
2605    Last_alloc_var=1             ! first var allocated will be var 2
2606    Vars_allocated=0
2607    Source_last=-1
2608    Object_last=-1
2609    Old_object_last=-1
2610    List_last=-1
2611    !
2612    Max_32_int=(2^31)-1
2613    Min_32_int=-(2^31)
2614    Max_16_int=(2^15)-1
2615    Min_16_int=-(2^15)
2616    !
2617    MAT List$= ("")
2618    MAT Info$= ("")
2619    !
2620    !      Check out parameter arrays to see if they are indexed correctly
2621    !
2622    IF BASE(Object,1)<>0 THEN 
2623      Error_string$="Object(*) index must start at zero"
2624      GOSUB Icode_init_err
2625    END IF
2626    IF BASE(Source$,1)<>0 THEN 
2627      Error_string$="Source(*) index must start at zero"
2628      GOSUB Icode_init_err
2629    END IF
2630    IF Enable_list_arg THEN 
2631      IF BASE(List$,1)<>0 THEN 
2632        Error_string$="Listing array index must start at zero"
2633        GOSUB Icode_init_err
2634      END IF
2635      ON ERROR GOTO Icode_list_lerr !List$(*) must be at least 80 chars wide
2636      List$(0)=RPT$(" ",80)          ! Even though List$ elements have 80
2637      List$(0)=""                    ! chars doesn't mean that they are
2638      IF 0 THEN                      ! large enough.
2639 Icode_list_lerr:OFF ERROR 
2640        Error_string$="List$(*) elements should be GREATER than 80 chars"
2641        Enable_list=0
2642        GOSUB Icode_init_err
2643      END IF
2644    END IF
2645    !
2646    GOSUB Icode_chk_info           !  Check Info$(*) for correct dimensions
2647    !
2648    ! Do Pre-pass.  Go through pseudo-op    section of ICODE program and
2649    ! find out how large tables must be.
2650    !
2651    Var_tbl_size=0
2652    Blkvar_tbl_size=0
2653    Blkext_tbl_size=0
2654    Blkcon_tbl_size=0
2655    Const_tbl_size=0
2656    !
2657    DISP Disp_line$;"  Doing Pre-pass."
2658 Icode_def_loop:                     ! Pre-pass: Just get table size info
2659    Enable_list=0                    ! Disable listing for pre-pass.
2660    Def_loop_done=0
2661    REPEAT
2662      GOSUB Icode_next_line
2663      GOSUB Icode_skip_lbl
2664      GOSUB Icode_get_opcod
2665      GOSUB Icode_init_inst
2666      SELECT Opcode$
2667      CASE "VAR"
2668        Var_tbl_size=Var_tbl_size+1
2669      CASE "DEFBLK_VAR"
2670        Blkvar_tbl_size=Blkvar_tbl_size+1
2671      CASE "DEFBLK_SP","DEFBLK_MAIN","DEFBLK_EXT"
2672        Blkext_tbl_size=Blkext_tbl_size+2
2673      CASE "DEFBLK_CON"
2674        Blkcon_tbl_size=Blkcon_tbl_size+1
2675      CASE "CONST"
2676        Const_tbl_size=Const_tbl_size+1
2677      CASE "DEF_END"
2678        Def_loop_done=1
2679      CASE "LBL_TBL_SIZE"
2680        Enable_const=1
2681        GOSUB Icode_get_arg
2682        IF Missing_arg THEN 
2683          Error_string$="Missing LBL_TBL_SIZE parameter"
2684          GOSUB Icode_err
2685        ELSE
2686          IF Arg>0 AND Arg<32767 THEN 
2687            Lbl_tbl_size=Arg
2688          ELSE
2689            Error_string$="Invalid LBL_TBL_SIZE specification - '"&VAL$(Arg)&"'"
2690            GOSUB Icode_err
2691          END IF
2692        END IF
2693      CASE "FORLBL_TBL_SIZE"
2694        Enable_const=1
2695        GOSUB Icode_get_arg
2696        IF Missing_arg THEN 
2697          Error_string$="Missing FORLBL_TBL_SIZE parameter"
2698          GOSUB Icode_err
2699        ELSE
2700          IF Arg>0 AND Arg<32767 THEN 
2701            Forlbl_tbl_size=Arg
2702          ELSE
2703            Error_string$="Invalid FORLBL_TBL_SIZE specification - '"&VAL$(Arg)&"'"
2704            GOSUB Icode_err
2705          END IF
2706        END IF
2707      CASE "ERR_ABRT_COUNT"
2708        Enable_const=1
2709        GOSUB Icode_get_arg
2710        IF Missing_arg THEN 
2711          Error_string$="Missing ERR_ABRT_COUNT parameter"
2712          GOSUB Icode_err
2713        ELSE
2714          IF Arg>0 AND Arg<1000 THEN 
2715            Err_abrt_count=Arg
2716          ELSE
2717            Error_string$="Invalid ERR_ABRT_COUNT specification - '"&VAL$(Arg)&"'"
2718            GOSUB Icode_err
2719          END IF
2720        END IF
2721      CASE "ERR_DISP_LINES"
2722        Enable_const=1
2723        GOSUB Icode_get_arg
2724        IF Missing_arg THEN 
2725          Error_string$="Missing ERR_DISP_LINES parameter"
2726          GOSUB Icode_err
2727        ELSE
2728          IF Arg>=0 AND Arg<100 THEN 
2729            Err_disp_lines=Arg
2730          ELSE
2731            Error_string$="Invalid ERR_DISP_LINES specification - '"&VAL$(Arg)&"'"
2732            GOSUB Icode_err
2733          END IF
2734        END IF
2735      CASE ELSE
2736        CALL Icode_inst_str(Opcode$,Inst_info$)
2737        IF Inst_info$<>"-1" OR Opcode$="EL_COMPLETO" THEN Def_loop_done=1
2738      END SELECT
2739      GOSUB Icode_next_inst
2740    UNTIL Def_loop_done
2741    !
2742    Enable_list=Enable_list_arg     ! Enable listing of so desired
2743    !
2744    GOSUB Icode_alloc_tbl           ! Allocate all internal tables
2745    !
2746    Source_last=-1                  ! reset pointer into source array
2747    List_last=-1                    ! and listing array
2748    !
2749    !     Allocate variable space.  Variable space needs to be allocated
2750    !     for all VAR, DEFBLK_VAR, DEFBLK_SP, DEFBLK_MAIN, and DEFBLK_EXT
2751    !     pseudo-ops. Don't forget, variables start at 2.
2752    DISP Disp_line$;"  Allocating variable space."
2753 Icode_alloc_var:!
2754    Vars_allocated=Var_tbl_size+Blkvar_tbl_size+Blkext_tbl_size+2
2755    IF Vars_allocated<>0 THEN        ! allocate room in ICODE prog for vars
2756      Object(0)=49                   ! insert c_goto around variable space
2757      Object(1)=0                    ! programs can't be greater than 32K
2758      Real_temp=Vars_allocated*2
2759      IF Real_temp>=Object_size THEN 
2760        Error_string$="Object code array too small for required variable space"
2761        GOSUB Icode_fatal_err
2762      END IF
2763      Object(2)=Real_temp
2764      FOR I=3 TO Real_temp-1         ! Set all vars to 0. Dont' really need
2765        Object(I)=0                  ! to do this.
2766      NEXT I
2767      Object_last=Real_temp-1
2768    END IF
2769    !
2770    !  Insert listing header into List$(*)
2771    !
2772    IF Enable_list THEN 
2773      List_last=List_last+1
2774      IF List_last<List_size THEN 
2775        ON ERROR GOTO Icode_list_len
2776        List$(List_last)="ICODE Assembler version "&Version$&".  Assembled  "&DATE$(TIMEDATE)&"  "&TIME$(TIMEDATE)
2777        OFF ERROR 
2778        IF 0 THEN 
2779 Icode_list_len:OFF ERROR 
2780          Error_string$="Listing lines need to be longer"
2781          Enable_list=0
2782          GOSUB Icode_fatal_err
2783        END IF
2784      ELSE
2785        Error_string$="Listing table overflow"
2786        GOSUB Icode_fatal_err
2787      END IF
2788    END IF
2789    !
2790    IF Info_info=2 THEN 
2791      !
2792      ! For each instruction, an entry is made into Info$(*). Each entry
2793      ! consists of the address of the opcode and the source$(*) line
2794      ! index. Only need for the debugger. i.e. Info_info=2
2795      !
2796      Info_inst_base=Info_hdr_size
2797      Inst_cnt=0
2798    END IF
2799    !
2800    IF Enable_list_arg THEN 
2801      DISP Disp_line$;"  Assembling.   Listing Enabled"
2802    ELSE
2803      DISP Disp_line$;"  Assembling."
2804    END IF
2805    !
2806    !   This loop assembles  the pseudo-op   section of the ICODE program.
2807    !   This loop is terminated when a non-pseudo-op instruction is
2808    !   found.
2809    !
2810 Icode_tbl_loop:!
2811    Tbl_loop_done=0
2812    REPEAT
2813      GOSUB Icode_next_line          ! find next instruction
2814      GOSUB Icode_skip_lbl           ! don't really want to look at labels
2815      GOSUB Icode_get_opcod          ! get Opcode$
2816      GOSUB Icode_init_inst          ! Init ptrs for listing and errs
2817      SELECT Opcode$
2818 Icode_var:!
2819      CASE "VAR"
2820        Enable_const=0                  ! Variable name may not be a CONST
2821        GOSUB Icode_get_arg             ! returns Arg$, Arg, and Missing_arg
2822        IF Missing_arg OR Arg$="" THEN 
2823          Error_string$="Missing variable name"
2824          GOSUB Icode_err
2825        ELSE
2826          Variable$=Arg$
2827          Enable_const=1                ! Init value may be a CONST
2828          GOSUB Icode_get_arg
2829          IF Missing_arg THEN 
2830            Error_string$="Missing or invalid variable init value"
2831            GOSUB Icode_err
2832          ELSE
2833            IF Arg>Max_32_int OR Arg<Min_32_int THEN 
2834              Error_string$="Invalid variable init value - '"&VAL$(Arg)&"'"
2835              GOSUB Icode_err
2836            ELSE
2837              IF Arg$[1;1]="@" THEN ! Is init val another variables var number
2838                Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2])
2839                IF Var_pos=-1 THEN 
2840                  Error_string$="Undefined variable reference - '"&Arg$[2]&"'"
2841                  GOSUB Icode_err
2842                ELSE
2843                  Arg=Var_num(Var_pos)
2844                END IF
2845              ELSE
2846                IF Arg$<>"" THEN 
2847                  Error_string$="Invalid variable init value - '"&Arg$&"'"
2848                  GOSUB Icode_err
2849                END IF
2850              END IF
2851            END IF
2852          END IF
2853          IF Error_string$="" THEN 
2854            Var_last=Var_last+1
2855            Last_alloc_var=Last_alloc_var+1
2856            Var_name$(Var_last)=Variable$
2857            Var_num(Var_last)=Last_alloc_var
2858            Lib_32_to_16(Arg,Int_hi,Int_lo)
2859            Object(Last_alloc_var*2)=Int_hi
2860            Object(Last_alloc_var*2+1)=Int_lo
2861            IF Enable_list THEN 
2862              List$(Old_list_last)[1;15]=IVAL$(Last_alloc_var*2,16)&" "&IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16)
2863            END IF
2864          END IF
2865        END IF
2866 Defblk_var:!
2867      CASE "DEFBLK_VAR"
2868        Enable_const=0                   ! Block name may not be a CONST
2869        GOSUB Icode_get_arg              ! returns Arg$, Arg and Missing_arg
2870        IF Missing_arg OR LEN(Arg$)=0 THEN 
2871          Error_string$="Missing DEFBLK_VAR block name"
2872          GOSUB Icode_err
2873        ELSE
2874          Block_name$=Arg$
2875          Enable_const=1                  ! Init value may be a CONST
2876          GOSUB Icode_get_arg
2877          IF Missing_arg OR Arg$<>"" THEN 
2878            Error_string$="Missing or invalid DEFBLK_VAR init value"
2879            GOSUB Icode_err
2880          ELSE
2881            IF Arg>Max_32_int OR Arg<Min_32_int THEN 
2882              Error_string$="Invalid DEFBLK_VAR init value - '"&VAL$(Arg)&"'"
2883              GOSUB Icode_err
2884            ELSE
2885              Blkvar_last=Blkvar_last+1
2886              Last_alloc_var=Last_alloc_var+1
2887              Blkvar_name$(Blkvar_last)=Block_name$
2888              Blkvar_id(Blkvar_last)=Last_alloc_var
2889              CALL Lib_32_to_16(Arg,Int_hi,Int_lo)
2890              Object(Last_alloc_var*2)=Int_hi
2891              Object(Last_alloc_var*2+1)=Int_lo
2892              IF Enable_list THEN 
2893                List$(List_last)[1;15]=IVAL$(Last_alloc_var*2,16)&" "&IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16)
2894              END IF
2895            END IF
2896          END IF
2897        END IF
2898            !
2899 Defblk_con:!
2900      CASE "DEFBLK_CON"
2901        Enable_const=0                  ! Block_name may not be a CONST
2902        GOSUB Icode_get_arg             ! returns Token$ and Error_flag
2903        IF Missing_arg OR LEN(Arg$)=0 THEN 
2904          Error_string$="Missing DEFBLK_CON block name"
2905          GOSUB Icode_err
2906        ELSE
2907          Block_name$=Arg$
2908          Enable_const=1                ! block_id may be a CONST
2909          GOSUB Icode_get_arg
2910          IF Missing_arg OR Arg$<>"" THEN 
2911            Error_string$="Missing or invalid DEFBLK_CON constant value"
2912            GOSUB Icode_err
2913          ELSE
2914            IF (Arg<=0 OR Arg>=32768) THEN 
2915              Error_string$="Illegal DEFBLK_CON init value"
2916              GOSUB Icode_err
2917            ELSE
2918              IF Error_string$="" THEN 
2919                Blkcon_last=Blkcon_last+1
2920                Blkcon_name$(Blkcon_last)=Block_name$
2921                Blkcon_id(Blkcon_last)=Arg
2922                IF Enable_list THEN List$(Old_list_last)[6;4]=IVAL$((Arg),16)
2923              END IF
2924            END IF
2925          END IF
2926        END IF
2927      !
2928 Defblk_main:!
2929 Defblk_sp:!
2930      CASE "DEFBLK_SP","DEFBLK_MAIN"
2931        IF Info_info=0 THEN 
2932          Error_string$="Can't use "&Opcode$&" without Info$ array"
2933          GOSUB Icode_err
2934        ELSE
2935          Block_type=1
2936          IF Opcode$[8]="SP" THEN Block_type=2
2937          Enable_const=0              ! Block_name may not be a CONST
2938          GOSUB Icode_get_arg         ! returns Arg$, Arg, and Missing_arg
2939          IF Missing_arg OR LEN(Arg$)=0 THEN 
2940            Error_string$="Missing "&Opcode$&" block name"
2941            GOSUB Icode_err
2942          ELSE
2943            Block_name$=Arg$
2944            Enable_const=1            ! block_size may be a CONST
2945            GOSUB Icode_get_arg
2946            IF Missing_arg OR Arg$<>"" OR Arg<=0 OR Arg>Max_32_int THEN 
2947              Error_string$="Missing or invalid "&Opcode$&" block size"
2948              GOSUB Icode_err
2949            ELSE
2950              Block_size=Arg
2951              Blkext_last=Blkext_last+1
2952              Last_alloc_var=Last_alloc_var+2
2953              Enable_const=1          ! header_block_size may be a CONST
2954              GOSUB Icode_get_arg
2955              IF Missing_arg OR Arg$<>"" OR Arg<0 THEN 
2956                Error_string$="Missing or invalid "&Opcode$&" header size"
2957                GOSUB Icode_err
2958              ELSE
2959                Header_size=Arg
2960              END IF
2961              Blkext_name$(Blkext_last)=Block_name$
2962              Blkext_id(Blkext_last)=(Last_alloc_var-1)
2963              Blkext_type(Blkext_last)=Block_type
2964              Blkext_size(Blkext_last)=Block_size
2965              Blkext_hsize(Blkext_last)=Header_size
2966              IF Enable_list THEN 
2967                List$(Old_list_last)[1;14]=IVAL$((Last_alloc_var-1)*2,16)&" ****,****"
2968              END IF
2969            END IF
2970          END IF
2971        END IF
2972        !
2973 Defblk_ext:!
2974      CASE "DEFBLK_EXT"
2975        Enable_const=0                 ! block_name may not be a CONST
2976        GOSUB Icode_get_arg            ! returns Arg$, Arg, and Missing_arg
2977        IF Missing_arg OR LEN(Arg$)=0 THEN 
2978          Error_string$="Missing DEFBLK_EXT block name"
2979          GOSUB Icode_err
2980        ELSE
2981          Blkext_last=Blkext_last+1
2982          Last_alloc_var=Last_alloc_var+2
2983          Blkext_name$(Blkext_last)=Arg$
2984          Blkext_id(Blkext_last)=(Last_alloc_var-1)
2985          Blkext_type(Blkext_last)=0
2986          Blkext_size(Blkext_last)=-1
2987          Blkext_hsize(Blkext_last)=-1
2988          IF Enable_list THEN 
2989            List$(Old_list_last)[1;14]=IVAL$((Last_alloc_var-1)*2,16)&" ****,****"
2990          END IF
2991        END IF
2992        !
2993 Const:!
2994      CASE "CONST"
2995        DIM Constant_name$[16]
2996        Enable_const=0                 ! New CONST_name may not be a CONST
2997        GOSUB Icode_get_arg            ! returns Arg$, Arg, and Missing_arg
2998        IF Missing_arg OR LEN(Arg$)=0 THEN 
2999          Error_string$="Missing CONST constant name"
3000          GOSUB Icode_err
3001        ELSE
3002          Constant_name$=Arg$
3003          Enable_const=1               ! CONST value may be a CONST
3004          GOSUB Icode_get_arg
3005          IF Missing_arg OR LEN(Arg$)<>0 OR Arg<Min_32_int OR Arg>Max_32_int THEN 
3006            Error_string$="Missing or invalid CONST constant value"
3007            GOSUB Icode_err
3008          ELSE
3009            Const_last=Const_last+1
3010            Const_name$(Const_last)=Constant_name$
3011            Const_val(Const_last)=Arg
3012            IF Enable_list THEN List$(Old_list_last)[6;9]=IVAL$((Arg),16)
3013          END IF
3014        END IF
3015      CASE "ERR_ABRT_COUNT","ERR_DISP_LINES","LBL_TBL_SIZE","FORLBL_TBL_SIZE"
3016        GOSUB Icode_get_arg           ! This is a dummy get arg
3017      CASE "DEF_END"
3018        Tbl_loop_done=1
3019      CASE ELSE
3020        CALL Icode_inst_str(Opcode$,Inst_info$)
3021        IF Inst_info$<>"-1" OR Opcode$="EL_COMPLETO" OR Opcode$="ASM_OFF" THEN 
3022          Tbl_loop_done=1
3023          GOSUB Icode_back_line
3024        ELSE
3025          IF POS(Opcode$,",")<>0 THEN 
3026            Error_string$="Unexpected comma - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'"
3027          ELSE
3028            Error_string$="Undefined pseudo-op - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'"
3029          END IF
3030          Enable_list=0
3031          GOSUB Icode_fatal_err
3032        END IF
3033      END SELECT
3034      IF Error_string$="" AND Line$<>"" AND NOT Tbl_loop_done THEN 
3035        Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'"
3036        GOSUB Icode_err
3037      END IF
3038 Here:!
3039      Error_string$=""
3040    UNTIL Tbl_loop_done
3041    !
3042    !  This is the main assembly loop
3043    !
3044 Icode_asm_loop:!
3045    Asm_loop_done=0
3046    REPEAT
3047      Error_string$=""
3048      !
3049      GOSUB Icode_next_line
3050      !
3051      IF Line$="EL_COMPLETO" THEN 
3052        Asm_loop_done=1
3053      ELSE
3054        !
3055        IF Info_info=2 THEN GOSUB Icode_insrt_nop
3056        !
3057        IF Line$[1;1]="." THEN 
3058          Error_string$="Not expecting continuation line"
3059          GOSUB Icode_err
3060        ELSE
3061          GOSUB Icode_check_lbl           ! check for line label
3062          GOSUB Icode_get_opcod           ! returns Opcode$
3063          GOSUB Icode_init_inst           ! init ptrs for listing and errs
3064          !
3065          !  Get information about instruction. Opcode and parameters.
3066          !
3067          CALL Icode_inst_str(Opcode$,Inst_info$)
3068          Opcode_num=VAL(Inst_info$)
3069          !
3070          IF Opcode_num=-1 THEN 
3071            IF Opcode$="ASM_OFF" THEN 
3072              IF Info_info=2 THEN GOSUB Icode_info_isrt
3073              GOSUB Icode_asm_off
3074              GOSUB Icode_end_inst
3075              IF Error_string$="" AND Line$<>"" THEN 
3076                Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'"
3077                GOSUB Icode_err
3078              END IF
3079            ELSE
3080              Error_string$="Undefined Opcode - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'"
3081              GOSUB Icode_err
3082            END IF
3083          END IF
3084          !
3085          IF Opcode_num<>-1 THEN 
3086            Add_object=Opcode_num   ! add opcode to object array
3087            GOSUB Icode_add_obj
3088            !
3089            !  Put address of opcode and source line # into Info$(*).
3090            !
3091            IF Info_info=2 THEN GOSUB Icode_info_isrt
3092            !
3093            IF Error_string$="" THEN 
3094              Inst_info_ptr=POS(Inst_info$," ") ! skip opcode field
3095              IF Inst_info_ptr<>0 THEN 
3096                REPEAT
3097                  Inst_info_ptr=Inst_info_ptr+1 ! look at next parm char
3098                  SELECT Inst_info$[Inst_info_ptr;1]
3099                  CASE "L"                ! Label
3100                    GOSUB Icode_get_label
3101                  CASE "P"
3102                    GOSUB Icode_get_param ! 16 bit immediate integer
3103                  CASE "B"                ! CONST or VAR
3104                    GOSUB Icode_get_block ! DEFBLK_xxxx
3105                  CASE "V"
3106                    GOSUB Icode_get_var
3107                  CASE "I"                ! 32 bit immediate integer
3108                    GOSUB Icode_get_int   ! or CONST
3109                  CASE "S"                ! 'String'
3110                    GOSUB Icode_get_str
3111                  CASE "F"                ! Floating point
3112                    GOSUB Icode_get_float
3113                  CASE "M"                ! 16 bit immediate integer
3114                    GOSUB Icode_get_immed
3115                  CASE "R"                ! Instruction has a repeating
3116                    GOSUB Icode_rpt_str   ! field.
3117                  CASE "@"                ! Instruction has more than one
3118                    GOSUB Icode_mlty_inst ! form depending on last field.
3119                  END SELECT
3120                UNTIL Inst_info_ptr=LEN(Inst_info$)
3121                !
3122                IF Error_string$="" AND Line$<>"" THEN 
3123                  Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'"
3124                  GOSUB Icode_err
3125                END IF
3126              END IF
3127            END IF
3128            GOSUB Icode_end_inst
3129          END IF              ! If Opcode_num<>-1
3130        END IF
3131      END IF
3132    UNTIL Asm_loop_done
3133    !
3134    !  See if there are any unresolved forward references.
3135    !
3136    GOSUB Icode_forlbl_ck
3137    !
3138    Object_last=Object_last+1 ! HP-IB module needs extra word in prog block
3139    !
3140    GOSUB Icode_fill_info     ! Fill Info$(*) with tons of stuff
3141    GOSUB Icode_asm_exit      ! Final clean up and exit
3142    !
3143    ! ************ Assembler GOSUB Subroutines ***********************
3144    !
3145 Icode_subs:!
3146    IF 0 THEN 
3147      !
3148      !  This subroutine is used to repeat a section of the instruction info
3149      !  string.  The substring between the parameter code 'R' and the next
3150      !  '!' is repeated <count> times. <count> is specified by the last
3151      !  16 bit value places in the object array.
3152      !
3153 Icode_rpt_str:!
3154      Repeat_count=Object(Object_last)
3155      IF Repeat_count<0 THEN 
3156        Error_string$="Variable reference in immediate parameter field"
3157        GOSUB Icode_err
3158      ELSE
3159        Num_parms=POS(Inst_info$[Inst_info_ptr+1],"!")-1
3160        Repeat_str$=Inst_info$[Inst_info_ptr+1;Num_parms]
3161        Inst_info$=Inst_info$[1,Inst_info_ptr]&RPT$(Repeat_str$,Repeat_count)&Inst_info$[Inst_info_ptr+Num_parms+2]
3162      END IF
3163      RETURN 
3164      !
3165      !  This subroutine is used to select a section of the instruction
3166      !  parameter string.  When the first '@' is found, the last value
3167      !  added to Object(*) is used as a select value. The select value
3168      !  is used to select a section of the instruction parameter string.
3169      !  The section to be used is delimited by '@<select_value>' and
3170      !  the next '@' or end of string.
3171      !
3172 Icode_mlty_inst:!
3173      Rel_ptr=POS(Inst_info$[Inst_info_ptr],VAL$(Object(Object_last)))
3174      IF Rel_ptr=0 THEN 
3175        Error_string$="Invalid f_ready_ram <monitor> field"
3176        GOSUB Icode_err
3177      ELSE
3178        Inst_info$=Inst_info$[Inst_info_ptr+Rel_ptr-1]
3179        Inst_info_ptr=1
3180        Rel_ptr=POS(Inst_info$,"@")
3181        IF Rel_ptr<>0 THEN Inst_info$=Inst_info$[1,Rel_ptr-1]
3182      END IF
3183      RETURN 
3184      !
3185      !  This subroutine is used to insert information about the current
3186      !  instruction into Info$(*). The current opcode number and
3187      !  opcode Source(*) address are inserted into Info$(*).  This is
3188      !  used by the debugger. This subroutine is only called if
3189      !  Info_info=2
3190      !
3191 Icode_info_isrt:!
3192      ON ERROR GOTO Icode_isrt_err
3193      OUTPUT Temp$ USING "#,W,W";Old_object_last+1,Old_source_last
3194      Info$(Info_inst_base+Inst_cnt DIV 10)[((Inst_cnt MOD 10)*4)+1;4]=Temp$
3195      Inst_cnt=Inst_cnt+1
3196      !
3197      IF 0 THEN 
3198 Icode_isrt_err:!
3199        Error_string$="Info$ array not large enough"
3200        GOSUB Icode_fatal_err
3201      END IF
3202      !
3203      OFF ERROR 
3204      RETURN 
3205      !
3206      !  This subroutine is used to insert a c_nop before each user
3207      !  instruction.  The debugger needs this.  This subroutine should
3208      !  only be called if Info_info=2.
3209      !
3210 Icode_insrt_nop:!
3211      IF Enable_list THEN 
3212        List_last=List_last+1
3213        IF List_last>=List_size THEN 
3214          Error_string$="Listing table overflow"
3215          GOSUB Icode_fatal_err
3216        ELSE
3217          List$(List_last)=RPT$(" ",15)&RPT$(" ",15)&"<c_nop>"
3218        END IF
3219      END IF
3220      GOSUB Icode_init_inst
3221      Add_object=61                 ! insert c_nop
3222      GOSUB Icode_add_obj
3223      RETURN 
3224      !
3225      !  This instruction is used to init listing and error pointers
3226      !  to a new instruction state.
3227      !
3228 Icode_init_inst:!
3229      INTEGER Use_left_field,Add_stars
3230      Use_left_field=1
3231      Add_stars=0
3232      List_ptr=List_last
3233      Old_object_last=Object_last
3234      Old_source_last=Source_last
3235      Old_list_last=List_last
3236      Old_forlbl_last=Forlbl_last
3237      Error_string$=""
3238      RETURN 
3239      !
3240      !  This subroutine is used to clean up the List_last pointer after
3241      !  an instruction has been assembled. List_ptr is used by the
3242      !  Icode_add_obj subroutine to insert parameter values into the
3243      !  listing.  The Icode_next_line subroutine uses List_last.
3244      !
3245 Icode_end_inst:!
3246      IF Enable_list THEN 
3247        IF Use_left_field THEN 
3248          IF List_ptr-1>List_last THEN List_last=List_ptr-1
3249        ELSE
3250          IF List_ptr>List_last THEN List_last=List_ptr
3251        END IF
3252      END IF
3253      RETURN 
3254      !
3255      !  Input parameter: INTEGER Add_object, INTEGER Add_stars
3256      !
3257      !  This subroutine is used to add a opcode or parameter value to
3258      !  the object array.  This routine also puts this value into the
3259      !  listing. If Add_stars is set, then '****' is put into the listing
3260      !  instead of the Add_object value.
3261      !
3262 Icode_add_obj:!
3263      Object_last=Object_last+1
3264      IF Object_last>=Object_size THEN 
3265        Error_string$="Object(*) array overflow"
3266        GOSUB Icode_fatal_err
3267      END IF
3268      Object(Object_last)=Add_object
3269      IF Enable_list THEN 
3270        IF List_ptr>=List_size THEN 
3271          Error_string$="Listing table overflow"
3272          GOSUB Icode_fatal_err
3273          List_last=List_size-2
3274        ELSE
3275          IF Use_left_field THEN 
3276            List$(List_ptr)[1;4]=IVAL$(Object_last,16)
3277            IF Add_stars THEN 
3278              List$(List_ptr)[5;5]=" ****"
3279            ELSE
3280              List$(List_ptr)[5;5]=" "&IVAL$(Add_object,16)
3281            END IF
3282            Use_left_field=0
3283          ELSE
3284            IF Add_stars THEN 
3285              List$(List_ptr)[10;5]=",****"
3286            ELSE
3287              List$(List_ptr)[10;5]=","&IVAL$(Add_object,16)
3288            END IF
3289            List_ptr=List_ptr+1
3290            Use_left_field=1
3291          END IF
3292        END IF
3293      END IF
3294      RETURN 
3295      !
3296      !  This subroutine is called when an error occurs initialization.
3297      !
3298 Icode_init_err:!
3299      OUTPUT CRT
3300      FOR I=MAX(0,Source_last-Err_disp_lines) TO MIN(Source_last,Source_size-1)
3301        OUTPUT CRT;Source$(I)
3302      NEXT I
3303      GOSUB Icode_fatal_err
3304      RETURN 
3305      !
3306      !  This subroutine is called when an error causes the assembler
3307      !  to quit assembling.
3308      !
3309 Icode_fatal_err:!
3310      Error_count=Error_count+1
3311      Enable_list=Enable_list_arg
3312      IF Enable_list THEN 
3313        ON ERROR GOTO Icode_err_skip
3314        List_last=List_last+1
3315        IF List_last<List_size-1 THEN 
3316          List$(List_last)="***** FATAL ERROR: "&Error_string$&" *****"
3317        ELSE
3318          List_last=List_size-2
3319          List$(MAX(0,List_last))="***** FATAL ERROR: "&Error_string$&" *****"
3320        END IF
3321        OFF ERROR 
3322      END IF
3323 Icode_err_skip:Enable_list=0
3324      OFF ERROR 
3325      OUTPUT CRT;"***** FATAL ERROR: "&Error_string$;" *****"
3326      GOTO Icode_asm_exit
3327      RETURN 
3328      !
3329      !  This routine is called when routine error occurs.
3330      !
3331 Icode_err:!
3332      Error_count=Error_count+1
3333      !
3334      Object_last=Old_object_last             ! reset Object(*) ptr
3335      Forlbl_last=Old_forlbl_last             ! reset forward reference ptr
3336      !
3337      Use_left_field=1
3338      Add_object=-1                           ! overwrite opcode with -1
3339      GOSUB Icode_add_obj
3340      !
3341      Inst_info_ptr=LEN(Inst_info$)           ! don't get any more parms
3342      !
3343      IF Enable_list THEN                     ! clean up listing
3344        List$(Old_list_last)[6,15]="FFFF      "
3345        FOR I=Old_list_last+1 TO List_last
3346          List$(I)[1;15]=RPT$(" ",15)
3347        NEXT I
3348        List_last=List_last+1
3349        List$(List_last)=RPT$(" ",15)&"***** ERROR: "&Error_string$&" *****"
3350      END IF
3351      !
3352      !  Print out section of source code on CRT
3353      !
3354      OUTPUT CRT
3355      FOR I=MAX(Old_source_last-Err_disp_lines,0) TO MIN(Source_last,Source_size-1)
3356        OUTPUT CRT;Source$(I)
3357      NEXT I
3358      OUTPUT CRT;"***** ERROR: ";Error_string$;" *****"
3359      !
3360      IF Error_count>Err_abrt_count THEN  ! See if there are too many errors
3361        Error_string$="ICODE program has many problems"
3362        GOSUB Icode_fatal_err
3363      ELSE
3364        GOSUB Icode_next_inst
3365      END IF
3366      RETURN 
3367      !
3368      !  This subroutine is used to find the next line with a new
3369      !  instruction on it.
3370      !
3371 Icode_next_inst:!
3372      REPEAT
3373        GOSUB Icode_next_line
3374      UNTIL Line$[1,1]<>"."
3375      GOSUB Icode_back_line
3376      RETURN 
3377      !
3378      !  This subroutine is used by the pre-pass to skip labels.
3379      !  Labels are looked at in the main assembly loop.
3380      !
3381 Icode_skip_lbl:!
3382      Line_ptr=POS(Line$[1,17],":")
3383      IF Line_ptr<>0 THEN Line$=TRIM$(Line$[Line_ptr+1])
3384      RETURN 
3385      !
3386      !  This subroutine is used to see if the current line has a label
3387      !  on it.  If it does, then it is added to the label table.  Then
3388      !  the forward reference table is searched.  Each instance of a
3389      !  forward reference to the newly found label is then resolved.
3390      !
3391 Icode_check_lbl:!                                check for label in line$
3392      REPEAT
3393        Line_ptr=POS(Line$[1,17],":")
3394        IF Line_ptr<>0 THEN              ! looks like we have a label
3395          !
3396          Label$=Line$[1,Line_ptr-1]
3397          Line$=TRIM$(Line$[Line_ptr+1])
3398          !
3399          Lbl_last=Lbl_last+1
3400          IF Lbl_last<Lbl_tbl_size THEN 
3401            Lbl_name$(Lbl_last)=Label$
3402            !
3403            !  If Info_info=2 then the label must point to the c_nop
3404            !  that was inserted before this instruction.
3405            !
3406            IF Info_info=2 THEN 
3407              Lbl_loc(Lbl_last)=Object_last
3408              Lbl_src_loc(Lbl_last)=Source_last
3409            ELSE
3410              Lbl_loc(Lbl_last)=Object_last+1
3411            END IF
3412          ELSE
3413            Error_string$="Label table overflow"
3414            GOSUB Icode_err
3415            RETURN 
3416          END IF
3417          !
3418          !  Now, resolve all unresolved references to this label
3419          !
3420          REPEAT
3421            Forlbl_pos=FNIcode_search(Forlbl_name$(*),Forlbl_last,Label$)
3422            IF Forlbl_pos<>-1 THEN 
3423              !
3424              !  Found forward reference to this label. Resolve it.
3425              !
3426              Int_hi=0                   ! hi word must be zero
3427              Int_lo=Lbl_loc(Lbl_last)   ! use same addr as put in lbl table
3428              Object(Forlbl_loc(Forlbl_pos))=Int_hi              ! Addr hi
3429              Object(Forlbl_loc(Forlbl_pos)+1)=Int_lo            ! Addr lo
3430              !
3431              !  Move last element in forward reference list into this pos
3432              !
3433              Forlbl_name$(Forlbl_pos)=Forlbl_name$(Forlbl_last)
3434              Forlbl_loc(Forlbl_pos)=Forlbl_loc(Forlbl_last)
3435              !
3436              IF Enable_list THEN          ! Must also fill in listing.
3437                IF Forlbl_list_lft(Forlbl_pos) THEN 
3438                  List$(Forlbl_list_pos(Forlbl_pos))[6;9]=IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16)
3439                ELSE
3440                  List$(Forlbl_list_pos(Forlbl_pos))[10;5]=","&IVAL$(Int_hi,16)
3441                  List$(Forlbl_list_pos(Forlbl_pos)+1)[6;5]=IVAL$(Int_lo,16)
3442                END IF
3443                Forlbl_list_lft(Forlbl_pos)=Forlbl_list_lft(Forlbl_last)
3444                Forlbl_list_pos(Forlbl_pos)=Forlbl_list_pos(Forlbl_last)
3445              END IF
3446              Forlbl_last=Forlbl_last-1    ! One less forward reference now
3447            END IF
3448          UNTIL Forlbl_pos=-1
3449        END IF
3450        !
3451        !  If label was only thing on line, then we still need to check for
3452        !  a label on the next line.
3453        IF Line$="" THEN 
3454          IF Enable_list THEN List$(List_last)[1;4]=IVAL$(Object_last+1,16)
3455          GOSUB Icode_next_line
3456          Line_ptr=POS(Line$[1,17],":")
3457        END IF
3458      UNTIL Line$<>"" AND Line$<>"EL_COMPLETO" AND Line_ptr=0
3459      RETURN 
3460      !
3461      !  This subroutine is used to get Opcode$ out of the current input
3462      !  line.
3463      !
3464 Icode_get_opcod:!
3465      Line_ptr=POS(Line$," ")
3466      IF Line_ptr=0 THEN 
3467        Opcode$=Line$[1,MIN(20,LEN(Line$))]
3468        Line$=""
3469      ELSE
3470        Opcode$=Line$[1,MIN(Line_ptr-1,20)]
3471        Line$=TRIM$(Line$[Line_ptr+1])
3472      END IF
3473      RETURN 
3474      !
3475      !  This subroutine is used when the next parameter in the current
3476      !  instruction is an ICODE address (c_goto label_name).  Note that
3477      !  must be a string.  i.e. not absolute jumps.
3478      !
3479 Icode_get_label:!
3480      Enable_const=0                  ! Label field may not be a CONST
3481      GOSUB Icode_get_arg
3482      IF Arg$="" THEN 
3483        Error_string$="Missing label specification"
3484        GOSUB Icode_err
3485      ELSE
3486        !
3487        !   Search label table
3488        !
3489        Lbl_pos=FNIcode_search(Lbl_name$(*),Lbl_last,Arg$)
3490        IF Lbl_pos<>-1 THEN              ! found it
3491          Add_object=0
3492          GOSUB Icode_add_obj
3493          Add_object=Lbl_loc(Lbl_pos)
3494          GOSUB Icode_add_obj
3495        ELSE
3496          Forlbl_last=Forlbl_last+1      ! insert in forward reference table
3497          Forlbl_name$(Forlbl_last)=Arg$
3498          Forlbl_loc(Forlbl_last)=Object_last+1
3499          IF Enable_list THEN 
3500            Forlbl_list_pos(Forlbl_last)=List_ptr
3501            Forlbl_list_lft(Forlbl_last)=Use_left_field
3502          END IF
3503          Add_stars=1                   ! put stars in listing until this
3504          Add_object=0                  ! reference is resolved.
3505          GOSUB Icode_add_obj
3506          Add_object=0
3507          GOSUB Icode_add_obj
3508          Add_stars=0
3509        END IF
3510      END IF
3511      RETURN 
3512      !
3513      !  Input:   Enable_const
3514      !  Output:  Arg$, REAL Arg,  INTEGER Missing_arg
3515      !
3516      !  This routine is used to get the next parameter from the Source$(*)
3517      !  array.  The next parameter may be on the current line or on a
3518      !  continuation line.  The next parameter may be terminated by a
3519      !  space, comma or an end-of-line.  If the parameter is itself a
3520      !  numerical value, either decimal or hex ($<hex_num>), then Arg is
3521      !  set to the value and Arg$="".  If the parameter isn't a numerical
3522      !  value then Arg is undefined and Arg$ is set the the parameter
3523      !  string. If Enable_const is active, then the CONST table is searched
3524      !  to see if Arg$ is defined.
3525      !
3526 Icode_get_arg:                      ! returns Arg$, Arg and Missing_arg
3527      Missing_arg=0
3528      WHILE Line$=""
3529        GOSUB Get_cont_line          ! returns Line$ and Missing_arg
3530      END WHILE
3531      IF Missing_arg THEN 
3532        Arg$=""
3533        Arg=-1
3534      ELSE
3535        Line_ptr=POS(Line$,",")      ! Is there a comma delimiter
3536        IF Line_ptr=0 THEN           ! Nope
3537          Line_ptr=POS(Line$," ")
3538          IF Line_ptr=0 THEN 
3539            Arg$=Line$
3540            Line$=""
3541          ELSE
3542            Arg$=Line$[1,MIN(16,Line_ptr-1)]
3543            Line$=TRIM$(Line$[Line_ptr+1])
3544          END IF
3545        ELSE                         ! Yup
3546          Int_temp=POS(Line$," ")    ! Now see if there is a space between
3547                                     ! the end of the param and the comma.
3548          IF Int_temp<>0 THEN Line_ptr=MIN(Int_temp,Line_ptr)  ! Yes
3549          Arg$=TRIM$(Line$[1,MIN(16,Line_ptr-1)])
3550          IF Arg$="" THEN 
3551            Missing_arg=1
3552          ELSE
3553            IF Line$[Line_ptr;1]="," THEN   ! Remove Arg$ from Line$
3554              Line$=TRIM$(Line$[Line_ptr+1])
3555            ELSE
3556              Line$=TRIM$(Line$[Line_ptr+1])
3557              IF Line$[1,1]="," THEN Line$=TRIM$(Line$[2])
3558            END IF
3559          END IF
3560        END IF
3561        !                                            See if Arg$ has a
3562        CALL Icode_eval_str(Arg$,Arg,Missing_arg)  ! numerical value.
3563        IF Arg$<>"" AND Enable_const THEN 
3564          Const_pos=FNIcode_search(Const_name$(*),Const_last,Arg$)
3565          IF Const_pos<>-1 THEN 
3566            Arg=Const_val(Const_pos)
3567            Arg$=""
3568          END IF
3569        END IF
3570      END IF
3571      RETURN 
3572      !
3573      !  Output: Line$, Missing_arg
3574      !
3575      !  This subroutine is used to get a continuation line from the Source$(*)
3576      !  array. If the next line isn't a continuation line (first non space
3577      !  char on line must be '.'), then  Missing_arg is set true.
3578      !
3579 Get_cont_line:!
3580      INTEGER Done_cont_line
3581      Done_cont_line=0
3582      REPEAT
3583        GOSUB Icode_next_line            ! returns Line$ and Skipped_lines
3584        IF Line$[1,1]<>"." OR Skipped_lines>0 THEN 
3585          Missing_arg=1
3586          GOSUB Icode_back_line
3587          Done_cont_line=1
3588        ELSE
3589          Line$=TRIM$(Line$[2])
3590          IF LEN(Line$)>=1 THEN Done_cont_line=1
3591        END IF
3592      UNTIL Done_cont_line
3593      RETURN 
3594      !
3595      !  This subroutine is used to move back one line in the Source$(*)
3596      !  array and the List$(*) array.
3597      !
3598 Icode_back_line:!
3599      Source_last=Source_last-1
3600      IF Enable_list THEN 
3601        List$(List_last)=""
3602        List_last=List_last-1
3603      END IF
3604      RETURN 
3605      !
3606      !  Output: Line$ and  Skipped_lines
3607      !
3608      !  This subroutine is used to get the next source line.  It check
3609      !  to see when the end of the Source$(*) array has been found. If
3610      !  so, then Line$="EL_COMPLETO".
3611      !
3612 Icode_next_line:!
3613      INTEGER Skipped_lines
3614      Skipped_lines=-1
3615      REPEAT
3616        Skipped_lines=Skipped_lines+1
3617        Source_last=Source_last+1
3618        IF Source_last>=Source_size THEN 
3619          Line$="EL_COMPLETO"
3620        ELSE
3621          Line$=Source$(Source_last)
3622        END IF
3623        !                           Insert line into List$(*)
3624        IF Enable_list THEN 
3625          List_last=List_last+1
3626          IF List_last>=List_size THEN 
3627            List_last=List_size-2
3628            Error_string$="Listing table overflow"
3629            GOSUB Icode_fatal_err
3630          END IF
3631          List_line_len=LEN(List$(List_last))
3632          ON ERROR GOTO Icode_lstr_smal  ! List$ elements may be too small
3633          IF List_line_len=0 THEN 
3634            List$(List_last)=RPT$(" ",15)&Line$
3635          ELSE
3636            IF List_line_len<=15 THEN List$(List_last)=List$(List_last)&RPT$(" ",15-List_line_len)&Line$
3637          END IF
3638          OFF ERROR 
3639        END IF
3640        !
3641        !  Strip off comments.  This assumes no '!' inside string parameter.
3642        !  Also, convert everything to upper case.
3643        !
3644        Line_ptr=POS(Line$,"!")
3645        IF Line_ptr<>0 THEN 
3646          Line$=UPC$(TRIM$(Line$[1,Line_ptr-1]))
3647        ELSE
3648          Line$=UPC$(TRIM$(Line$))
3649        END IF
3650      UNTIL LEN(Line$)<>0
3651      !                      If an error occurs during the assignment of
3652      IF 0 THEN            ! Line$ to List$( ), then a jump is made to
3653 Icode_lstr_smal:OFF ERROR ! this section of code.
3654        Error_string$="List$(*) lines need to be longer"
3655        GOSUB Icode_fatal_err
3656      END IF
3657      RETURN 
3658      !
3659 Icode_asm_off:              ! This routine is used to put semi-unassembled
3660      INTEGER Arg_count      ! data into the program.  The first field after
3661      INTEGER Current_arg    ! ASM_OFF is the count and must be immediate,
3662      Enable_const=1         ! or CONST The next <count> fields must be
3663      GOSUB Icode_get_arg    ! immediate, CONST, VAR.
3664      IF Missing_arg THEN 
3665        Error_string$="Expecting ASM_OFF parameter count"
3666        GOSUB Icode_err
3667        RETURN 
3668      END IF
3669      IF Arg$<>"" THEN 
3670        Error_string$="ASM_OFF parameter count must be immediate"
3671        GOSUB Icode_err
3672        RETURN 
3673      END IF
3674      IF Arg<1 OR Arg>100 THEN 
3675        Error_string$="Invalid ASM_OFF parameter count field"
3676        GOSUB Icode_err
3677        RETURN 
3678      END IF
3679      Arg_count=Arg
3680      FOR Current_arg=1 TO Arg_count
3681        Enable_const=1
3682        GOSUB Icode_get_arg
3683        IF Missing_arg THEN 
3684          Error_string$="Expecting ASM_OFF parameter"
3685          GOSUB Icode_err
3686          RETURN 
3687        END IF
3688        IF Arg$<>"" THEN      ! and VARs may also be in the data stream.
3689          IF Arg$[1;1]="@" THEN 
3690            Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2])
3691            IF Var_pos<>-1 THEN 
3692              Arg=-(Var_num(Var_pos)+16384)
3693            ELSE
3694              Error_string$="Indirect variable undefined - '"&Arg$[2]&"'"
3695              GOSUB Icode_err
3696              RETURN 
3697            END IF
3698          ELSE
3699            Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$)
3700            IF Var_pos<>-1 THEN 
3701              Arg=-Var_num(Var_pos)
3702            ELSE
3703              Error_string$="Undefined symbol - '"&Arg$&"'"
3704              GOSUB Icode_err
3705              RETURN 
3706            END IF
3707          END IF
3708        END IF
3709        IF Arg>Max_16_int OR Arg<Min_16_int THEN 
3710          Error_string$="Invalid ASM_OFF parameter value - '"&VAL$(Arg)&"'"
3711          GOSUB Icode_err
3712          RETURN 
3713        END IF
3714        Add_object=Arg
3715        GOSUB Icode_add_obj
3716      NEXT Current_arg
3717      RETURN 
3718      !
3719      !  This subroutine is used to assemble a 32 bit integer parameter from
3720      !  from the source code.  The parameter must be a CONST reference or
3721      !  an immediate in line value.
3722      !
3723 Icode_get_int:!
3724      Enable_const=1
3725      GOSUB Icode_get_arg
3726      IF Missing_arg THEN 
3727        Error_string$="Missing 32 bit integer parameter"
3728        GOSUB Icode_err
3729        RETURN 
3730      END IF
3731      IF Arg$<>"" THEN 
3732        Error_string$="Undefined CONST - '"&Arg$&"'"
3733        GOSUB Icode_err
3734        RETURN 
3735      END IF
3736      IF Arg>Max_32_int OR Arg<Min_32_int THEN 
3737        Error_string$="Invaid integer parameter - '"&VAL$(Arg)&"'"
3738        GOSUB Icode_err
3739        RETURN 
3740      END IF
3741      CALL Lib_32_to_16(Arg,Int_hi,Int_lo)
3742      Add_object=Int_hi
3743      GOSUB Icode_add_obj
3744      Add_object=Int_lo
3745      GOSUB Icode_add_obj
3746      RETURN 
3747      !
3748      !  This subroutine is used to assemble a 16 bit integer parameter from
3749      !  from the source code.  The parameter must be a CONST reference or
3750      !  an immediate in line value.
3751      !
3752 Icode_get_immed:!
3753      Enable_const=1
3754      GOSUB Icode_get_arg
3755      IF Missing_arg THEN 
3756        Error_string$="Missing immediate data parameter"
3757        GOSUB Icode_err
3758        RETURN 
3759      END IF
3760      IF Arg$<>"" OR Arg>Max_16_int OR Arg<Min_16_int THEN 
3761        IF Arg$<>"" THEN 
3762          Error_string$="Invalid immediate parameter - '"&Arg$[1,MIN(20,LEN(Arg$))]&"'"
3763        ELSE
3764          Error_string$="Invalid immediate parameter - '"&VAL$(Arg)&"'"
3765        END IF
3766        GOSUB Icode_err
3767        RETURN 
3768      END IF
3769      Add_object=Arg
3770      GOSUB Icode_add_obj
3771      RETURN 
3772      !
3773      !  This subroutine is used to assemble an immediate floating point
3774      !  number from the source code.  Number may also be a CONST
3775      !
3776 Icode_get_float:!
3777      INTEGER I1,I2,I3,I4
3778      Enable_const=1
3779      GOSUB Icode_get_arg
3780      IF Missing_arg THEN 
3781        Error_string$="Missing floating point parameter"
3782        GOSUB Icode_err
3783        RETURN 
3784      END IF
3785      IF Arg$<>"" THEN 
3786        Error_string$="Undefined floating point CONST - '"&Arg$&"'"
3787        GOSUB Icode_err
3788        RETURN 
3789      END IF
3790      CALL Lib_float_to_64(Arg,I1,I2,I3,I4)
3791      Add_object=I1
3792      GOSUB Icode_add_obj
3793      Add_object=I2
3794      GOSUB Icode_add_obj
3795      Add_object=I3
3796      GOSUB Icode_add_obj
3797      Add_object=I4
3798      GOSUB Icode_add_obj
3799      RETURN 
3800      !
3801      !  This routine is used to assemble a string parameter.  This string
3802      !  must be between single quotes.  ICODE instructions that call for
3803      !  a string parameter also call for a string length word.  The
3804      !  assembler will count the length of the string and insert the string
3805      !  length field for the user.
3806      !
3807 Icode_get_str:!
3808      INTEGER Str_len
3809      Missing_arg=0
3810      WHILE Line$=""
3811        GOSUB Get_cont_line
3812      END WHILE
3813      IF Missing_arg THEN 
3814        Error_string$="Missing string parameter"
3815        GOSUB Icode_err
3816        RETURN 
3817      END IF
3818      IF Line$[1;1]<>"'" THEN 
3819        Error_string$="Missing first ' in string parameter"
3820        GOSUB Icode_err
3821      ELSE
3822        Line$=Line$[2]
3823        Str_len=POS(Line$,"'")
3824        IF Str_len=0 THEN 
3825          Error_string$="Missing second ' in string parameter"
3826          GOSUB Icode_err
3827        ELSE
3828          Str_len=Str_len-1
3829          Arg$=Line$[1,Str_len]
3830          Line$=Line$[Str_len+2]
3831          IF Str_len MOD 2=1 THEN 
3832            Arg$=Arg$&" "              ! string should fall on word boundary
3833            Str_len=Str_len+1
3834          END IF
3835          Add_object=Str_len
3836          GOSUB Icode_add_obj
3837          FOR I=1 TO Str_len STEP 2
3838            Add_object=256*NUM(Arg$[I])+NUM(Arg$[I+1])
3839            GOSUB Icode_add_obj
3840          NEXT I
3841        END IF
3842      END IF
3843      RETURN 
3844      !
3845      !  This subroutine is used to assemble a 'general' parameter.
3846      !  General means that it can be immediate, CONST or VAR.
3847      !
3848 Icode_get_param:!
3849      Enable_const=1
3850      GOSUB Icode_get_arg
3851      IF Missing_arg THEN 
3852        Error_string$="Missing parameter"
3853        GOSUB Icode_err
3854        RETURN 
3855      END IF
3856      IF Arg$<>"" THEN 
3857        IF Arg$[1;1]="@" THEN 
3858          Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2])
3859          IF Var_pos=-1 THEN 
3860            Error_string$="Undefined indirect variable - '"&Arg$[2]&"'"
3861            GOSUB Icode_err
3862            RETURN 
3863          END IF
3864          Arg=-(Var_num(Var_pos)+16384)
3865        ELSE
3866          Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$)
3867          IF Var_pos<>-1 THEN 
3868            Arg=-Var_num(Var_pos)
3869          ELSE
3870            Error_string$="Undefined parameter symbol - '"&Arg$&"'"
3871            GOSUB Icode_err
3872            RETURN 
3873          END IF
3874        END IF
3875      END IF                          ! IF 0 THEN
3876      IF Arg>Max_16_int OR Arg<Min_16_int THEN 
3877        Error_string$="Invalid parameter value - '"&VAL$(Arg)&"'"
3878        GOSUB Icode_err
3879        RETURN 
3880      END IF
3881      Add_object=Arg
3882      GOSUB Icode_add_obj
3883      RETURN 
3884      !
3885      !  This subroutine is used to assemble a block id parameter.
3886      !  The block may be DEFBLK_VAR, DEFBLK_CON, DEFBLK_SP, DEFBLK_MAIN
3887      !  or DEFBLK_EXT.
3888      !
3889 Icode_get_block:!
3890      INTEGER Blk_id_arg,Blk_index
3891      Enable_const=0
3892      GOSUB Icode_get_arg
3893      IF Arg$="" THEN 
3894        Error_string$="Illegal immediate block specification"
3895        GOSUB Icode_err
3896      ELSE
3897        IF Arg$[1;1]="^" THEN 
3898          Blk_index=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$[2])
3899          IF Blk_index=-1 THEN 
3900            IF FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$[2])<>-1 OR FNIcode_search(Blkcon_name$(*),Blkcon_last,Arg$[2])<>-1 THEN 
3901              Error_string$="'"&Arg$[2]&"'  is not of auto allocate class"
3902              GOSUB Icode_err
3903            ELSE
3904              Error_string$="Undefined auto allocate block - '"&Arg$[2]&"'"
3905              GOSUB Icode_err
3906            END IF
3907          ELSE
3908            IF Blkext_hsize(Blk_index)=0 THEN 
3909              Error_string$="No header allocated for '"&Arg$[2]&"'"
3910              GOSUB Icode_err
3911            ELSE
3912              Blk_id_arg=-(Blkext_id(Blk_index)+1)
3913            END IF
3914          END IF
3915        ELSE
3916          Blk_index=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$)
3917          IF Blk_index<>-1 THEN 
3918            Blk_id_arg=-Blkext_id(Blk_index)
3919          ELSE
3920            Blk_index=FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$)
3921            IF Blk_index<>-1 THEN 
3922              Blk_id_arg=-Blkvar_id(Blk_index)
3923            ELSE
3924              Blk_index=FNIcode_search(Blkcon_name$(*),Blkcon_last,Arg$)
3925              IF Blk_index<>-1 THEN 
3926                Blk_id_arg=Blkcon_id(Blk_index)
3927              ELSE
3928                Error_string$="Undefined block - '"&Arg$&"'"
3929                GOSUB Icode_err
3930                RETURN 
3931              END IF
3932            END IF
3933          END IF
3934        END IF
3935      END IF
3936      Add_object=Blk_id_arg
3937      GOSUB Icode_add_obj
3938      RETURN 
3939      !
3940      !  This subroutine is used to assemble a variable reference parameter.
3941      !  A DEFBLK_VAR parameter may also be used in this field.
3942      !
3943 Icode_get_var:!
3944      Enable_const=0
3945      GOSUB Icode_get_arg
3946      IF Arg$<>"" THEN 
3947        IF Arg$[1;1]="@" THEN    ! Is this an indirect variable
3948          Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2])
3949          IF Var_pos=-1 THEN 
3950            Error_string$="Undefined indirect variable - '"&Arg$[2]&"'"
3951            GOSUB Icode_err
3952          ELSE
3953            Arg=-(Var_num(Var_pos)+16384)
3954          END IF
3955        ELSE
3956          Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$)
3957          IF Var_pos<>-1 THEN 
3958            Arg=-Var_num(Var_pos)
3959          ELSE
3960            IF Arg$[1;1]="^" THEN           ! Header block
3961              Blkext_pos=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$[2])
3962              IF Blkext_pos<>-1 THEN 
3963                IF Blkext_hsize(Blkext_pos)>0 THEN 
3964                  Arg=Blkext_id(Blkext_pos)+1
3965                ELSE
3966                  Error_string$="No header block allocated for '"&Arg$[2]&"'"
3967                  GOSUB Icode_err
3968                END IF
3969              ELSE
3970                Error_string$="'"&Arg$[2]&"' not of auto allocate class"
3971                GOSUB Icode_err
3972              END IF
3973            ELSE
3974              Blkext_pos=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$)
3975              IF Blkext_pos<>-1 THEN 
3976                Arg=-Blkext_id(Blkext_pos)
3977              ELSE
3978                Blkvar_pos=FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$)
3979                IF Blkvar_pos<>-1 THEN 
3980                  Arg=-Blkvar_id(Blkvar_pos)
3981                ELSE
3982                  Error_string$="Undefined variable - '"&Arg$&"'"
3983                  GOSUB Icode_err
3984                END IF
3985              END IF
3986            END IF
3987          END IF
3988        END IF
3989      END IF
3990      Add_object=Arg
3991      GOSUB Icode_add_obj
3992      RETURN 
3993      !
3994      !  This subroutine is used to allocate all the internal tables
3995      !  needed by the assembler.
3996      !
3997 Icode_alloc_tbl:!
3998      Lbl_last=-1
3999      ALLOCATE Lbl_name$(0:MAX(Lbl_tbl_size-1,0))[16],INTEGER Lbl_loc(0:MAX(Lbl_tbl_size-1,0))
4000      IF Info_info=2 THEN ALLOCATE INTEGER Lbl_src_loc(0:MAX(Lbl_tbl_size-1,0))
4001      Var_last=-1
4002      ALLOCATE Var_name$(0:MAX(Var_tbl_size-1,0))[16],INTEGER Var_num(0:MAX(Var_tbl_size-1,0))
4003      Forlbl_last=-1
4004      ALLOCATE Forlbl_name$(0:MAX(Forlbl_tbl_size-1,0))[16],INTEGER Forlbl_loc(0:MAX(Forlbl_tbl_size-1,0))
4005      IF Enable_list THEN ALLOCATE INTEGER Forlbl_list_pos(0:MAX(Forlbl_tbl_size-1,0)),INTEGER Forlbl_list_lft(0:MAX(Forlbl_tbl_size-1,0))
4006      Blkvar_last=-1
4007      ALLOCATE Blkvar_name$(0:MAX(Blkvar_tbl_size-1,0))[16],INTEGER Blkvar_id(0:MAX(Blkvar_tbl_size-1,0))
4008      Blkext_last=-1
4009      ALLOCATE Blkext_name$(0:MAX(Blkext_tbl_size-1,0))[16],INTEGER Blkext_id(0:MAX(Blkext_tbl_size-1,0))
4010      ALLOCATE INTEGER Blkext_type(0:MAX(Blkext_tbl_size-1,0))
4011      ALLOCATE Blkext_hsize(0:MAX(Blkext_tbl_size-1,0)),Blkext_size(0:MAX(Blkext_tbl_size-1,0))
4012      Blkcon_last=-1
4013      ALLOCATE Blkcon_name$(0:MAX(Blkcon_tbl_size-1,0))[16],INTEGER Blkcon_id(0:MAX(Blkcon_tbl_size-1,0))
4014      Const_last=-1
4015      ALLOCATE Const_name$(0:MAX(Const_tbl_size-1,0))[16],Const_val(0:MAX(Const_tbl_size-1,0))
4016      RETURN 
4017      !
4018      !  This subroutine is used to do some checks on Info$(*) to make sure
4019      !  that it is of the correct size.
4020      !
4021 Icode_chk_info:!
4022      Info_hdr_size=6
4023      IF Info_info>0 THEN 
4024        IF Info_size<Info_hdr_size THEN 
4025          Error_string$="Info$ array < "&VAL$(Info_hdr_size)&" elements"
4026          GOSUB Icode_init_err
4027        END IF
4028        IF BASE(Info$,1)<>0 THEN 
4029          Error_string$="Info$(*) index must start at zero"
4030          GOSUB Icode_init_err
4031        END IF
4032        ON ERROR GOTO Icode_info_smal     ! Each line must be 40 chars long
4033        FOR I=1 TO Info_hdr_size
4034          Info$(I)=RPT$(" ",40)
4035        NEXT I
4036        OFF ERROR 
4037        IF 0 THEN 
4038 Icode_info_smal:OFF ERROR 
4039          Error_string$="Info$(*) string elements < 40 chars"
4040          GOSUB Icode_init_err
4041        END IF
4042      END IF
4043      RETURN 
4044      !
4045 Icode_fill_info:!
4046!
4047!  This subroutine is used to fill the Info$(*) array after all
4048!  source code has been assembled will lots of little things
4049!  that the debugger, downloader, etc... need to know.
4050!
4051!  Info$(*) format:
4052!
4053!        char->0        1         2         3         4
4054!  line        1234567890123456789012345678901234567890
4055!    0         < a >< b >< c >< d >< e >
4056!    1         < i >< j >< k >< l >
4057!    2         < q >< r >< s >< t >
4058!    3         < x >< y >< z >
4059!    4         < F >< G >< H >
4060!    5         < I >< J >
4061!                                 .
4062!    k         <    Inst_info table                   >
4063!                                 .
4064!                                 .
4065!    i         <    Blkext table                      >
4066!                                 .
4067!                                 .
4068!    q         <    blkvar table                      >
4069!                                 .
4070!                                 .
4071!    x         <    Blkcon table                      >
4072!                                 .
4073!                                 .
4074!    F         <    Var    table                      >
4075!                                 .
4076!                                 .
4077!    I         <    Lbl    table                      >
4078!                                 .
4079!                                 .
4080!    z         <    Debugger history queue space      >
4081!                                 .
4082! a:  Info_info
4083! b:  ICODE program id
4084! c:  Info$(*) header size (6)
4085! d:  Info_size
4086! e:  # of vars reserved. For VAR, DEFBLK_VAR, etc...
4087!
4088! i:  Start of Blkext table in Info$(*)
4089! j:  # of Blkext table lines in Info$(*)
4090! k:  Object_size
4091! l:  Source_size
4092!
4093! q:  Start of Blkvar table in Info$(*)
4094! r:  # of Blkvar table lines in Info$(*)
4095! s:  Start of Instruction table in Info$(*)
4096! t:  # of Instructions in Info$(*). NOT # of instruction lines.
4097!
4098! x:  Start of Blkcon table in Info$(*)
4099! y:  # of Blkcon table lines in Info$(*)
4100! z:  Start of 3 lines in Info$(*) reserved for debugger history queue
4101!
4102! F:  Start of var table in Info$(*)
4103! G:  # of var table lines in Info$(*)
4104! H:  Object(*) address of last set break point. Used by debugger.
4105!
4106! I:  Start of label table in Info$(*)
4107! J:  # of label table lines in Info$(*)
4108!
4109! Inst_info table:  Each line may have information about a maximum of 10
4110!                   assembled instructions.  Information about a single
4111!                   instruction consists of 4 bytes.  These bytes are in
4112!                   binary format with the first 2 bytes indicating the
4113!                   object address and the second 2 bytes indicating the
4114!                   source address.
4115!
4116! Blkext table:  Each line has information about one DEFBLK_SP,DEFBLK_MAIN
4117!                or DEFBLK_EXT user defined block. Chars 1 through 16 are
4118!                the block name, char 17 is a mode byte, chars 18 through
4119!                22 hold the variable number, chars 23 through 28 hold
4120!                the block size, chars 29 through 34 hold the header block
4121!                size, and chars 35 through 39 hold the block id.  The
4122!                mode byte indicates the block type and whether or not
4123!                the downloader should allocate this block at download
4124!                time. Mode codes are as follows:
4125!                  0 - undefined yet
4126!                  1 - MAIN auto allocate block
4127!                  2 - SP   auto allocate block
4128!                  3 - MAIN user allocate block
4129!                  4 - SP   user allocate block
4130!
4131!  Blkvar table: Each line has information about one DEFBLK_VAR block.
4132!                Characters 1 through 16 hold the block name and chars
4133!                17 through 21 hold the variable number that contains the
4134!                block id.
4135!
4136!  Blkcon table: Each line has information about one DEFBLK_CON block.
4137!                Characters 1 through 16 hold the block name and chars
4138!                17 through 21 hold the block id.
4139!
4140!  Var table:    Each line has information about one VARiable. Characters
4141!                1 through 16 hold the variable name and chars 17 through
4142!                21 hold the variable number.
4143!
4144!  Lbl table:    Each line has information about one label.  Characters
4145!                1 through 16 hold the label name and chars 17 through 21
4146!                hold the label source address.
4147!
4148!  Debugger history queue space:  These 3 lines are used as storage space
4149!                                 by the debugger. The first line contains
4150!                                 2 fields. Chars 1 through 5 hold the
4151!                                 Hist_fifo_ptr and chars 6 through 10 hold
4152!                                 Hist_fifo_wrap.  The second line contains
4153!                                 the ICODE history object address list.
4154!                                 This list can hold up to 20 two byte
4155!                                 binary entries.  The third line contains
4156!                                 the ICODE history opcode list.  This list
4157!                                 can also hold up to 20 two byte binary
4158!                                 entries.  This list is used to hold the
4159!                                 ICODE history queue. See IHQ? HP-IB
4160!                                 command.
4161!
4162!
4163      IF Info_info<>0 THEN 
4164        !
4165        ! Find out how many lines need to be in Info$(*)
4166        !
4167        IF Info_info=1 THEN Lines_needed=Blkext_last+1+Info_hdr_size
4168        !
4169        IF Info_info=2 THEN 
4170          Info_inst_cnt=Inst_cnt DIV 10
4171          IF Inst_cnt MOD 10<>0 THEN Info_inst_cnt=Info_inst_cnt+1
4172          Lines_needed=MAX(Blkext_last,0)+MAX(Blkvar_last,0)+MAX(Blkcon_last,0)+MAX(Var_last,0)+MAX(Lbl_last,0)+MAX(Info_hdr_size,0)+6+Info_inst_cnt
4173          Lines_needed=Lines_needed+3  ! Debugger needs this space
4174        END IF                         ! to keep the history list
4175        !
4176        IF Lines_needed>Info_size THEN 
4177          Error_string$="Info$ array not large enough"
4178          GOSUB Icode_fatal_err
4179        END IF
4180        !
4181        REDIM Info$(0:Lines_needed-1)
4182        !
4183        !  Get indexes into Info$(*) where each table will go
4184        !
4185        Blkext_infostrt=Info_hdr_size+Info_inst_cnt
4186        Blkvar_infostrt=Blkext_infostrt+Blkext_last+1
4187        Blkcon_infostrt=Blkvar_infostrt+Blkvar_last+1
4188        Var_infostrt=Blkcon_infostrt+Blkcon_last+1
4189        Lbl_infostrt=Var_infostrt+Var_last+1
4190        !
4191        !  Start filling in Info$(*) with info.
4192        !
4193        IF Info_info=2 THEN 
4194          Dbg_infostrt=Lbl_infostrt+Lbl_last+1   !Reserve 3 lines for hist
4195                                                 ! table used by debugger.
4196          Info$(Dbg_infostrt)[1,5]=VAL$(-1)  ! Init Hist_fifo_ptr
4197          Info$(Dbg_infostrt)[6,10]=VAL$(0)  ! Init Hist_fifo_wrap
4198          Info$(Dbg_infostrt+1)=RPT$(" ",40)
4199          Info$(Dbg_infostrt+2)=RPT$(" ",40)
4200        END IF
4201        !
4202        Info$(0)[1,5]=VAL$(Info_info)
4203        Info$(0)[6,10]=VAL$(-1)
4204        Info$(0)[11,15]=VAL$(Info_hdr_size)
4205        Info$(0)[16,20]=VAL$(Lines_needed)
4206        Info$(0)[21,25]=VAL$(Vars_allocated)
4207        !
4208        IF Blkext_last=-1 THEN 
4209          Info$(1)[1,5]=VAL$(0)
4210        ELSE
4211          Info$(1)[1,5]=VAL$(Blkext_infostrt)
4212        END IF
4213        Info$(1)[6,10]=VAL$(Blkext_last+1)
4214        Info$(1)[11,15]=VAL$(Object_last+1)
4215        Info$(1)[16,20]=VAL$(Source_last)
4216        !
4217        IF Info_info=1 THEN 
4218          FOR I=2 TO 5
4219            Info$(I)[1,5]=VAL$(0)
4220            Info$(I)[6,10]=VAL$(0)
4221          NEXT I
4222        ELSE
4223          Info$(2)[1,5]=VAL$(Blkvar_infostrt)
4224          Info$(2)[6,10]=VAL$(Blkvar_last+1)
4225          Info$(2)[11,15]=VAL$(Info_inst_base)
4226          Info$(2)[16,20]=VAL$(Inst_cnt)
4227          Info$(3)[1,5]=VAL$(Blkcon_infostrt)
4228          Info$(3)[6,10]=VAL$(Blkcon_last+1)
4229          Info$(3)[11,15]=VAL$(Dbg_infostrt)     ! used by debugger
4230          Info$(4)[1,5]=VAL$(Var_infostrt)
4231          Info$(4)[6,10]=VAL$(Var_last+1)
4232          Info$(4)[11,15]=VAL$(-1)                ! used by debugger to
4233          Info$(5)[1,5]=VAL$(Lbl_infostrt)
4234          Info$(5)[6,10]=VAL$(Lbl_last+1)
4235          Info$(5)[11;1]=VAL$(0)                  ! Disp_vars_hex = 0
4236          Info$(5)[12;1]=VAL$(0)                  ! disp_blks_hex = 0
4237        END IF
4238        !
4239        !  Fill in externally allocated block table
4240        !
4241        Blkext_ptr=-1
4242        FOR I=Blkext_infostrt TO Blkext_infostrt+Blkext_last
4243          Blkext_ptr=Blkext_ptr+1
4244          Info$(I)[1,16]=Blkext_name$(Blkext_ptr)
4245          Info$(I)[17;1]=VAL$(Blkext_type(Blkext_ptr))
4246          Info$(I)[18,22]=VAL$(Blkext_id(Blkext_ptr))
4247          Info$(I)[23,28]=VAL$(Blkext_size(Blkext_ptr))
4248          Info$(I)[29,34]=VAL$(Blkext_hsize(Blkext_ptr))
4249        NEXT I
4250        !
4251        IF Info_info=2 THEN 
4252          !
4253          !  Fill in DEFBLK_VAR table
4254          !
4255          Blkvar_ptr=-1
4256          FOR I=Blkvar_infostrt TO Blkvar_infostrt+Blkvar_last
4257            Blkvar_ptr=Blkvar_ptr+1
4258            Info$(I)[1,16]=Blkvar_name$(Blkvar_ptr)
4259            Info$(I)[17,21]=VAL$(Blkvar_id(Blkvar_ptr))
4260          NEXT I
4261          !
4262          !  Fill in DEFBLK_CON table
4263          !
4264          Blkcon_ptr=-1
4265          FOR I=Blkcon_infostrt TO Blkcon_infostrt+Blkcon_last
4266            Blkcon_ptr=Blkcon_ptr+1
4267            Info$(I)[1,16]=Blkcon_name$(Blkcon_ptr)
4268            Info$(I)[17,21]=VAL$(Blkcon_id(Blkcon_ptr))
4269          NEXT I
4270          !
4271          !  Fill in variable table
4272          !
4273          Var_ptr=-1
4274          FOR I=Var_infostrt TO Var_infostrt+Var_last
4275            Var_ptr=Var_ptr+1
4276            Info$(I)[1,16]=Var_name$(Var_ptr)
4277            Info$(I)[17,21]=VAL$(Var_num(Var_ptr))
4278          NEXT I
4279          !
4280          !  Fill in label table
4281          !
4282          Lbl_ptr=-1
4283          FOR I=Lbl_infostrt TO Lbl_infostrt+Lbl_last
4284            Lbl_ptr=Lbl_ptr+1
4285            Info$(I)[1,16]=Lbl_name$(Lbl_ptr)
4286            Info$(I)[17,21]=VAL$(Lbl_loc(Lbl_ptr))
4287            Info$(I)[22,26]=VAL$(Lbl_src_loc(Lbl_ptr))
4288          NEXT I
4289        END IF               ! If info_info=2 then
4290      END IF                 ! If Info_info<>0 then
4291      RETURN 
4292      !
4293 Icode_forlbl_ck:       ! See if there are any unresolved forward references
4294      IF Forlbl_last>-1 THEN 
4295        FOR I=0 TO Forlbl_last
4296          Error_string$="ERROR: Undefined label - '"&Forlbl_name$(I)&"'"
4297          OUTPUT CRT;Error_string$
4298          Error_count=Error_count+1
4299          IF Enable_list THEN 
4300            List_last=List_last+1
4301            List$(MAX(0,MIN(List_last,List_size-1)))=RPT$(" ",15)&"***** "&Error_string$&" *****"
4302          END IF
4303        NEXT I
4304      END IF
4305      RETURN 
4306      !
4307 Icode_asm_exit:            ! This routine is used to exit the assembler
4308      Disp_line$="ICODE assembly complete.  "
4309      IF Error_count=0 THEN 
4310        Disp_line$=Disp_line$&"No errors.  "&VAL$(Source_last)&" source lines.  "&VAL$(Object_last+1)&" object words."
4311      ELSE
4312        BEEP 
4313        IF Error_count=1 THEN 
4314          Disp_line$=Disp_line$&VAL$(Error_count)&" error."
4315        ELSE
4316          Disp_line$=Disp_line$&VAL$(Error_count)&" errors."
4317          IF Error_count>20 THEN Disp_line$=Disp_line$&"   ICODE program needs work"
4318        END IF
4319      END IF
4320      DISP Disp_line$
4321      IF Enable_list THEN 
4322        List_last=List_last+1
4323        List$(MIN(List_last,List_size-1))=Disp_line$
4324      END IF
4325      REDIM List$(0:MAX(0,MIN(List_last,List_size-1)))
4326      IF Error_count=0 THEN 
4327        REDIM Source$(0:MAX(Source_last-1,0))
4328        REDIM Object(0:MAX(Object_last,0))
4329      END IF
4330      !
4331      IF Error_count<>0 THEN 
4332        ON ERROR GOTO Icode_who_cares
4333        REDIM Info$(0:0)
4334        Info$(0)="9"
4335 Icode_who_cares:IF 0 THEN A=1
4336        OFF ERROR 
4337      END IF
4338      !
4339      RETURN Error_count
4340    END IF                            ! GOSUBS IF 0 THEN
4341    !
4342  FNEND                               ! Icode_assemble
4343  !
4344 Icode_search:DEF FNIcode_search(Search_array$(*),Array_last,Search_key$)
4345!
4346!   This function is used by the assembler to search a table and return
4347!   an index into that table indicating where the search key was found.
4348!   <Search_array$> is the array to be searched. <Array_last> is the last
4349!   element in <Search_array$> that should be checked.  <Search_key$> is
4350!   what should be found in <Search_array$>.  If <Search_key$> is found
4351!   in <Search_array$> then the index into <Search_array$> is returned
4352!   in the function result, else -1 is returned.
4353!
4354    INTEGER I,Int_array_last
4355    Int_array_last=Array_last
4356    IF Int_array_last>=0 THEN 
4357      FOR I=0 TO Int_array_last
4358        IF Search_key$=Search_array$(I) THEN RETURN I
4359      NEXT I
4360    END IF
4361    RETURN -1
4362  FNEND
4363  !
4364 Icode_inst_str:SUB Icode_inst_str(Opcode$,Inst_info$)
4365!
4366!   This function is used by the assembler to translate an opcode mnemonic
4367!   (did you know that mnemonically is a word?) into an instruction
4368!   information string.  The instruction information string contains
4369!   the opcode number and a list of code which tell the assembler what
4370!   parameters must follow.  If the opcode mnemonic (who was the first
4371!   person to spell mnemonic?) is undefined, then "-1" is returned.
4372!   See the main assembly loop in the assembler for details on what the
4373!   parameter codes mean.
4374!
4375    SELECT Opcode$[1;2]
4376    CASE "C_"
4377      SELECT Opcode$[3]
4378      CASE "BEQ"
4379        Inst_info$="57 LPP"
4380      CASE "BGE"
4381        Inst_info$="59 LPP"
4382      CASE "BGT"
4383        Inst_info$="60 LPP"
4384      CASE "BITSET"
4385        Inst_info$="54 LPP"
4386      CASE "BLE"
4387        Inst_info$="56 LPP"
4388      CASE "BLT"
4389        Inst_info$="55 LPP"
4390      CASE "BNE"
4391        Inst_info$="58 LPP"
4392      CASE "END"
4393        Inst_info$="48"
4394      CASE "GOSUB"
4395        Inst_info$="50 L"
4396      CASE "GOTO"
4397        Inst_info$="49 L"
4398      CASE "NOP"
4399        Inst_info$="61"
4400      CASE "RTS"
4401        Inst_info$="51"
4402      CASE "SP_BEQ"
4403        Inst_info$="52 LP"
4404      CASE "SP_BNE"
4405        Inst_info$="53 LP"
4406      CASE ELSE
4407        Inst_info$="-1"
4408      END SELECT
4409    CASE "F_"
4410      SELECT Opcode$[3]
4411      CASE "ASSERT_TRIG"
4412        Inst_info$="22"
4413      CASE "BLK_MC68000"
4414        Inst_info$="32 BPMRBP!"
4415      CASE "COPY_BLOCK"
4416        Inst_info$="14 BB"
4417      CASE "EXEC"
4418        Inst_info$="134 P"
4419      CASE "FAST_AVG_ADD"
4420        Inst_info$="126 BPBPPP"
4421      CASE "FAST_AVG_DIV"
4422        Inst_info$="127 BPBPPP"
4423      CASE "FAST_AVG_INIT"
4424        Inst_info$="124 BPPPPP"
4425      CASE "FLOAT_ADD"
4426        Inst_info$="86 BPBPBPP"
4427      CASE "FLOAT_AVG"
4428        Inst_info$="132 BPBPPP"
4429      CASE "FLOAT_CCONST"
4430        Inst_info$="107 BPPFF"
4431      CASE "FLOAT_CDIV"
4432        Inst_info$="101 BPBPBPP"
4433      CASE "FLOAT_CMULT"
4434        Inst_info$="98 BPBPBPP"
4435      CASE "FLOAT_CONJ"
4436        Inst_info$="116 BPBPP"
4437      CASE "FLOAT_CONST"
4438        Inst_info$="104 BPPF"
4439      CASE "FLOAT_EXTREMAL"
4440        Inst_info$="120 BPBPP"
4441      CASE "FLOAT_DINTRLVE"
4442        Inst_info$="45 BPBPBPP"
4443      CASE "FLOAT_DIV"
4444        Inst_info$="95 BPBPBPP"
4445      CASE "FLOAT_INTRLVE"
4446        Inst_info$="83 BPBPBPP"
4447      CASE "FLOAT_LOG10"
4448        Inst_info$="125 BPBPP"
4449      CASE "FLOAT_MULT"
4450        Inst_info$="92 BPBPBPP"
4451      CASE "FLOAT_PHASE"
4452        Inst_info$="119 BPBPP"
4453      CASE "FLOAT_SQRT"
4454        Inst_info$="122 BPBPP"
4455      CASE "FLOAT_SUB"
4456        Inst_info$="89 BPBPBPP"
4457      CASE "FLOAT_TO_INT"
4458        Inst_info$="113 BPBPP"
4459      CASE "FLOAT_TO_SHORT"
4460        Inst_info$="112 BPBPP"
4461      CASE "FLOAT_WINGEN"
4462        Inst_info$="138 BPPMRF!"
4463      CASE "FLOAT_XYPOW"
4464        Inst_info$="128 BPBPBPP"
4465      CASE "GET_ASCII"
4466        Inst_info$="27 PMRV!"
4467      CASE "GET_GBL_STA","GET_GLB_STA"
4468        Inst_info$="30 V"
4469      CASE "GET_HDW_STATUS"
4470        Inst_info$="29 PV"
4471      CASE "GET_SIG"
4472        Inst_info$="46 V"
4473      CASE "GET_SRQ_MASK"
4474        Inst_info$="63 V"
4475      CASE "GET_STA"
4476        Inst_info$="15 V"
4477      CASE "GET_STATUS"
4478        Inst_info$="28 PV"
4479      CASE "GET_STC"
4480        Inst_info$="16 V"
4481      CASE "GLB_COMMAND"
4482        Inst_info$="24 PS"
4483      CASE "GLB_CONTROL"
4484        Inst_info$="26 V"
4485      CASE "HPIB_COMMAND"
4486        Inst_info$="17 S"
4487      CASE "INPUT_DATA"
4488        Inst_info$="1 PBPP"
4489      CASE "INT_TO_FLOAT"
4490        Inst_info$="111 BPBPP"
4491      CASE "INT_TO_SHORT"
4492        Inst_info$="110 BPBPP"
4493      CASE "KEEP_READY_RAM"
4494        Inst_info$="66"
4495      CASE "LOAD_PROG"
4496        Inst_info$="42 BP"
4497      CASE "LOAD_SP_ALGS"
4498        Inst_info$="47 P"
4499      CASE "MC68000"
4500        Inst_info$="31 IMRBP!"
4501      CASE "MOD_COMMAND"
4502        Inst_info$="23 PS"
4503      CASE "MOD_CONTROL"
4504        Inst_info$="25 PV"
4505      CASE "MOVE_BLOCK"
4506        Inst_info$="13 BPBPP"
4507      CASE "OFF_INT"
4508        Inst_info$="38"
4509      CASE "ON_IRQ"
4510        Inst_info$="35 L"
4511      CASE "ON_SHUTDOWN"
4512        Inst_info$="37 L"
4513      CASE "ON_SP"
4514        Inst_info$="36 L"
4515      CASE "ON_SRQ"
4516        Inst_info$="34 L"
4517      CASE "OUTPUT_DATA"
4518        Inst_info$="2 PBPP"
4519      CASE "PAUSE"
4520        Inst_info$="133"
4521      CASE "POLL_MODULE"
4522        Inst_info$="39 PV"
4523      CASE "READ_DISC"
4524        Inst_info$="5 BPPPPPPPV"
4525      CASE "READ_ROM"
4526        Inst_info$="136 PV"
4527      CASE "READ_SP_STAT"
4528        Inst_info$="118 V"
4529      CASE "READY_DISC"
4530        Inst_info$="7 PPPPPBPBPV"
4531      CASE "READY_RAM"
4532        Inst_info$="8 M@0BPPPMRP!@1BPBPV"
4533      CASE "RECEIVE_DATA"
4534        Inst_info$="3 BPP"
4535      CASE "RELEASE_BUS"
4536        Inst_info$="41 P"
4537      CASE "REQUEST_BUS"
4538        Inst_info$="40"
4539      CASE "SAMPLE"
4540        Inst_info$="137 BPBPPPP"
4541      CASE "SEND_DATA"
4542        Inst_info$="4 BPP"
4543      CASE "SET_EXP_DEF"
4544        Inst_info$="129 PPPP"
4545      CASE "SET_SRQ_MASK"
4546        Inst_info$="64 P"
4547      CASE "SET_WORK_ID"
4548        Inst_info$="139 B"
4549      CASE "SHORT_ADD"
4550        Inst_info$="84 BPBPBPP"
4551      CASE "SHORT_CCONST"
4552        Inst_info$="105 BPPPPP"
4553      CASE "SHORT_CDIV"
4554        Inst_info$="99 BPBPBPP"
4555      CASE "SHORT_CMULT"
4556        Inst_info$="96 BPBPBPP"
4557      CASE "SHORT_CONJ"
4558        Inst_info$="114 BPBPP"
4559      CASE "SHORT_CONST"
4560        Inst_info$="102 BPPPP"
4561      CASE "SHORT_DINTRLVE"
4562        Inst_info$="43 BPBPBPP"
4563      CASE "SHORT_DIV"
4564        Inst_info$="93 BPBPBPP"
4565      CASE "SHORT_INTRLVE"
4566        Inst_info$="81 BPBPBPP"
4567      CASE "SHORT_MULT"
4568        Inst_info$="90 BPBPBPP"
4569      CASE "SHORT_NORM"
4570        Inst_info$="135 BPP"
4571      CASE "SHORT_SUB"
4572        Inst_info$="87 BPBPBPP"
4573      CASE "SHORT_TO_FLOAT"
4574        Inst_info$="109 BPBPP"
4575      CASE "SHORT_TO_INT"
4576        Inst_info$="108 BPBPP"
4577      CASE "SIG_PROC"
4578        Inst_info$="0 PMRM!MRBP!"
4579      CASE "SIGNAL"
4580        Inst_info$="18 P"
4581      CASE "STORE_PROG"
4582        Inst_info$="62 BPPP"
4583      CASE "SYNC"
4584        Inst_info$="33"
4585      CASE "SYNC_TIME"
4586        Inst_info$="130 P"
4587      CASE "THRUPUT"
4588        Inst_info$="9 PP"
4589      CASE "TRIG_SEQ"
4590        Inst_info$="10"
4591      CASE "TRIG_SEQ_TIME"
4592        Inst_info$="121 P"
4593      CASE "UNASSERT_TRIG"
4594        Inst_info$="21"
4595      CASE "UNDEFINED"
4596        Inst_info$="44"
4597      CASE "WAIT_FOR_SIG"
4598        Inst_info$="19 V"
4599      CASE "WAIT_TO_SIG"
4600        Inst_info$="65 P"
4601      CASE "WAIT_SRQ"
4602        Inst_info$="20"
4603      CASE "WRITE_DISC"
4604        Inst_info$="6 BPPPPPPPV"
4605      CASE "WRITE_ROM"
4606        Inst_info$="123 PP"
4607      CASE "WRITE_SP_CNTL"
4608        Inst_info$="117 P"
4609      CASE "XFER_TO_HOST"
4610        Inst_info$="11 PP"
4611      CASE "XFER_TO_MOD"
4612        Inst_info$="12 PP"
4613      CASE ELSE
4614        Inst_info$="-1"
4615      END SELECT
4616    CASE "V_"
4617      SELECT Opcode$[3]
4618      CASE "ADD"
4619        Inst_info$="71 PPV"
4620      CASE "AND"
4621        Inst_info$="68 PPV"
4622      CASE "CEQUATE"
4623        Inst_info$="75 IV"
4624      CASE "DIV"
4625        Inst_info$="74 PPV"
4626      CASE "GET16_INDEXED"
4627        Inst_info$="77 BPV"
4628      CASE "GET32_INDEXED"
4629        Inst_info$="78 BPV"
4630      CASE "MODULO"
4631        Inst_info$="70 PPV"
4632      CASE "MULT"
4633        Inst_info$="73 PPV"
4634      CASE "NOT"
4635        Inst_info$="67 PV"
4636      CASE "OR"
4637        Inst_info$="69 PPV"
4638      CASE "PUT16_INDEXED"
4639        Inst_info$="79 BPV"
4640      CASE "PUT32_INDEXED"
4641        Inst_info$="80 BPV"
4642      CASE "SUB"
4643        Inst_info$="72 PPV"
4644      CASE "VEQUATE"
4645        Inst_info$="76 VV"
4646      CASE ELSE
4647        Inst_info$="-1"
4648      END SELECT
4649    CASE ELSE
4650      Inst_info$="-1"
4651    END SELECT
4652  SUBEND
4653  !
4654 Icode_eval_str:SUB Icode_eval_str(Str$,Str_val,Str_error)
4655!
4656!   This subprogram is used to evaluate a string into a numerical quantity.
4657!   <Str$> is the input string and its numerical value (if there is one) is
4658!   returned in <Str_val>.  This will work on decimal and hex numbers. Hex
4659!   numbers must be preceeded by a '$'.  If <Str$> can not be converted
4660!   into a number then <Str_error> is set to 1.  <Str_error> is also set
4661!   to 1 if <Str$>="".
4662!
4663    Str_error=0
4664    ON ERROR GOTO Icode_no_value
4665    IF Str$="" THEN 
4666      Str_error=1
4667    ELSE
4668      IF Str$[1;1]="$" THEN 
4669        Str_val=DVAL(Str$[2],16)
4670        Str$=""
4671      ELSE
4672        Str_val=VAL(Str$)
4673        Str$=""
4674      END IF
4675    END IF
4676    IF 0 THEN 
4677 Icode_no_value:Str_val=-1
4678    END IF
4679    OFF ERROR 
4680  SUBEND
4681  !
4682 Icode_dld:DEF FNIcode_dld(INTEGER Object(*),INTEGER Enable_info,Info$(*))
4683!
4684!   This function is used to allocate an ICODE program block, allocate
4685!   some types of data blocks, and download the ICODE program into its
4686!   program block.  <Object(*)> is the assembled ICODE program.
4687!   <Enable_info> is a flag which enables the downloader to search <Info$>
4688!   for unallocated blocks. If <Enable_info> is non-zero, then <Info$> is
4689!   searched for all DEFBLK_SP and DEFBLK_MAIN block types.  These blocks
4690!   are then allocated.  Also, DEFBLK_EXT block types that have been
4691!   flagged by 'FNIcode_def_ext' to be allocated by the downloader are
4692!   allocated.  To find out the block id of any block, 'FNIcode_ext_id'
4693!   may be used after the ICODE program has been downloaded.  If
4694!   <Enable_info> is zero, then no blocks are allocated (except the ICODE
4695!   program block).  Returned in the function result is the block id of
4696!   the ICODE program.  If an error occurs, then an error message is
4697!   displayed and a -1 is returned as the function result.
4698!
4699    DIM Line$[40],Error_string$[100],Temp$[20]
4700    Object_size=SIZE(Object,1)
4701    IF NOT FNIcode_info_ok(Info$(*),Error_string$) THEN GOTO Icode_dld_err
4702    !
4703    IF Enable_info THEN 
4704      ON ERROR GOTO Icode_info_bad
4705      Blkext_strt=VAL(Info$(1)[1,5])
4706      Blkext_cnt=VAL(Info$(1)[6,10])
4707      FOR I=Blkext_strt TO Blkext_strt+Blkext_cnt-1
4708        Line$=Info$(I)
4709        Block_type=VAL(Line$[17;1])
4710        IF Block_type=0 THEN 
4711          Error_string$="Block '"&TRIM$(Line$[1,16])&"' not allocated"
4712          GOTO Icode_dld_err
4713          RETURN -1
4714        ELSE
4715          Var_number=VAL(Line$[18,22])
4716          Block_size=VAL(Line$[23,28])
4717          Hblock_size=VAL(Line$[29,34])
4718          IF Var_number<0 OR Var_number>32767 THEN GOTO Icode_info_bad
4719          IF Block_size<0 THEN GOTO Icode_info_bad
4720          IF Hblock_size<0 THEN Icode_info_bad
4721          IF Block_type=1 OR Block_type=2 THEN 
4722            OFF ERROR 
4723            IF Block_type=1 THEN 
4724              Temp$=FNHw_cmd_rsp$("NEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3)
4725            ELSE
4726              Temp$=FNHw_cmd_rsp$("SNEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3)
4727            END IF
4728            IF FNHw_io_error THEN GOTO Icode_hw_io_err
4729            ON ERROR GOTO Icode_info_bad
4730            Block_id=VAL(Temp$)
4731            IF Block_id=-1 THEN GOTO Icode_id_bad
4732            IF Block_id>32767 THEN GOTO Icode_info_bad
4733            Info$(I)[35,39]=VAL$(Block_id)
4734          ELSE
4735            Block_id=VAL(Info$(I)[35,39])
4736          END IF
4737          Var_base=Var_number*2
4738          ON ERROR GOTO Icode_obj_bad
4739          Object(Var_base)=0
4740          Object(Var_base+1)=Block_id
4741          IF Hblock_size>0 THEN 
4742            Object(Var_base+2)=0
4743            Object(Var_base+3)=Block_id+1
4744          END IF
4745        END IF
4746      NEXT I
4747    END IF
4748    !
4749    OFF ERROR 
4750    Temp$=FNHw_cmd_rsp$("NEW "&VAL$(SIZE(Object,1))&";NEW?",3)
4751    IF FNHw_io_error THEN GOTO Icode_hw_io_err
4752    Prog_id=VAL(Temp$)
4753    IF Prog_id=-1 THEN 
4754      Error_string$="Can not allocate program block"
4755      GOTO Icode_dld_err
4756    END IF
4757    !
4758    Hw_write_blk(Prog_id,Object(*),5)
4759    IF FNHw_io_error THEN GOTO Icode_hw_io_err
4760    !
4761    IF Enable_info THEN 
4762      Info$(0)[6,10]=VAL$(Prog_id)
4763    END IF
4764    !
4765    RETURN Prog_id
4766    !
4767    IF 0 THEN 
4768 Icode_obj_bad:!
4769      Error_string$="Object(*) access error"
4770      GOTO Icode_dld_err
4771 Icode_id_bad:!
4772      Error_string$="Could not allocate block data block"
4773      GOTO Icode_dld_err
4774 Icode_hw_io_err:!
4775      Error_string$="Hardware I/O timeout error"
4776      GOTO Icode_dld_err
4777 Icode_info_bad:!
4778      Error_string$="Info$ array format error"
4779      GOTO Icode_dld_err
4780 Icode_dld_err:OFF ERROR 
4781      Icode_exec_err("Icode_dld: "&Error_string$)
4782      RETURN -1
4783    END IF
4784  FNEND
4785  !
4786 Icode_ext_id:DEF FNIcode_ext_id(Block_name$,Info$(*))
4787!
4788!  This function is used to get the id of an ICODE defined block. Since
4789!  auto allocate blocks are not allocated until download time, this function
4790!  will not return valid data until the ICODE program has been downloaded.
4791!  The block name is specified by <Block_name$> and the block id is returned
4792!  in the function result.  If there is an error (block not allocated yet,
4793!  etc), then -1 will be returned.
4794!
4795    DIM Error_string$[100]
4796    IF FNIcode_info_ok(Info$(*),Error_string$) THEN 
4797      Info_pos=VAL(Info$(1)[1,5])
4798      Info_max=Info_pos+VAL(Info$(1)[6,10])-1
4799      Block_name$=UPC$(TRIM$(Block_name$))
4800      WHILE Info_pos<=Info_max
4801        IF Block_name$[1;1]="^" THEN 
4802          IF Block_name$[2]=TRIM$(Info$(Info_pos)[1,16]) THEN 
4803            IF VAL(Info$(Info_pos)[29,34])>0 THEN 
4804              Auto_id=VAL(Info$(Info_pos)[35,39])
4805            ELSE
4806              Icode_exec_err("Icode_auto_id: No header block allocated")
4807              RETURN -1
4808            END IF
4809          END IF
4810        ELSE
4811          IF Block_name$=TRIM$(Info$(Info_pos)[1,16]) THEN 
4812            Auto_id=VAL(Info$(Info_pos)[35,39])
4813            RETURN Auto_id
4814          END IF
4815        END IF
4816        Info_pos=Info_pos+1
4817      END WHILE
4818    ELSE
4819      Icode_exec_err("Icode_auto_id: "&Error_string$)
4820      RETURN -1
4821    END IF
4822    RETURN -1
4823  FNEND
4824  !
4825 Icode_info_ok:DEF FNIcode_info_ok(Info$(*),Error_string$)
4826!
4827!   This function is used (not by the assembler) to see if the Info$ array
4828!   is of the correct format.  This routine is here because every ICODE
4829!   file subprogram that accesses <Info$> needs to make sure that it does
4830!   not bomb out because the user didn't pass in the correct array.
4831!   Returned in the function result is a 1 if <Info$> seems ok.  If a
4832!   problem is found with <Info$> then <Error_string$> is used to return
4833!   an error string.
4834!
4835    DIM Line$[40]
4836    !
4837    Error_string$=""
4838    !
4839    IF BASE(Info$,1)<>0 THEN          ! Check index
4840      Error_string$="Info$ index must start at zero"
4841      RETURN 0
4842    END IF
4843    !
4844    ON ERROR GOTO Icode_str_smal
4845    Line$[1;40]=Info$(0)              ! make sure 40 chars wide
4846    Info$(0)=RPT$(" ",40)
4847    Info$(0)=Line$
4848    !
4849    !   Check info_info field
4850    !
4851    ON ERROR GOTO Icode_info_bad
4852    Info_info=VAL(Line$[1,5])
4853    IF Info_info<0 OR Info_info>2 THEN GOTO Icode_info_bad
4854    !
4855    Header_size_chk=VAL(Info$(0)[11,15])  ! get header size
4856    !
4857    !   Now see if size make sense.
4858    !
4859    Total_size=VAL(Info$(0)[16,20])
4860    IF SIZE(Info$,1)<Header_size_chk OR SIZE(Info$,1)<Total_size THEN 
4861      Error_string$="Info$ format error - Info$ too small"
4862      RETURN 0
4863    END IF
4864    !
4865    RETURN 1
4866    !
4867    IF 0 THEN 
4868 Icode_info_bad:Error_string$="Info$ format error"
4869      RETURN 0
4870 Icode_str_smal:Error_string$="Info$ format error -  < 40 chars"
4871      RETURN 0
4872    END IF
4873  FNEND
4874  !
4875 Icode_exec_err:SUB Icode_exec_err(Error_string$)
4876!
4877!   This function is used to display an error message on the screen.
4878!   The screen is cleared, the error message is displayed, this routine
4879!   then waits 3 seconds and returns.
4880!
4881    BEEP 
4882    OUTPUT CRT;"                                                          "
4883    OUTPUT CRT
4884    OUTPUT CRT;"*** ";Error_string$;" ***"
4885    OUTPUT CRT
4886    WAIT 3
4887  SUBEND
4888  !
4889 Icode_def_ext:DEF FNIcode_def_ext(Block_name$,Use_main_ram,Block_size,Hblock_size,Block_id,Info$(*))
4890!
4891!   This function is used to bind a DEFBLK_EXT block name with a block id.
4892!   The block to be bound is specified by <Block_name$>.  If the block is
4893!   an HP3565S HP-IB module MAIN data RAM block, then <Use_main_ram> should
4894!   be non-zero.  If the block is to reside in SP data RAM, then
4895!   <Use_main_ram> should be zero.  <Info$(*)> is the information array
4896!   that was filled with all sorts of information from the assembler. There
4897!   are two modes this function can be used in.  If <Block_id> is <= 0
4898!   then mode 1 is used.  In mode 1, <Block_size> and <Hblock_size> define
4899!   the sizes of the data block and header data block.  These blocks will
4900!   be allocated for the user by the downloader (FNIcode_dld).
4901!   If <block_id> > 0 then mode 2 is used. In mode 2, the user has already
4902!   allocated the block and is just telling the downloader what the
4903!   block id is.  In mode 2, <Block_size> and <Hblock_size> must also
4904!   contain the size of the data block and header block. In either
4905!   case, the function result will be the block id of block specified.
4906!   If an error occurs during the execution of this function, then an
4907!   error message is displayed, and a -1 is returned as the function
4908!   result. Note that this function should be used after the program is
4909!   is assembled and before the program is downloaded.
4910!
4911    DIM Line$[40],Error_string$[40]
4912    INTEGER Found_match
4913    IF LEN(Block_name$)>16 THEN 
4914      Icode_exec_err("Icode_def_ext: Block_name$ parameter string too long")
4915      RETURN -1
4916    END IF
4917    IF Block_size<0 THEN 
4918      Icode_exec_err("Icode_def_ext: Invalid Block_size parameter")
4919      RETURN -1
4920    END IF
4921    IF Hblock_size<0 THEN 
4922      Icode_exec_err("Icode_def_ext: Invalid header block size parameter")
4923      RETURN -1
4924    END IF
4925    IF Block_id<0 THEN 
4926      Icode_exec_err("Icode_def_ext: Invalid Block_id parameter")
4927      RETURN -1
4928    END IF
4929    IF FNIcode_info_ok(Info$(*),Error_string$) THEN 
4930      Block_name$=UPC$(TRIM$(Block_name$))
4931      Info_pos=VAL(Info$(1)[1,5])
4932      Info_max=Info_pos+VAL(Info$(1)[6,10])
4933      Found_match=0
4934      WHILE Info_pos<Info_max AND NOT Found_match
4935        IF Block_name$=TRIM$(Info$(Info_pos)[1,16]) THEN 
4936          Found_match=1
4937          IF Block_id=0 THEN 
4938            IF Use_main_ram THEN 
4939              Temp$=FNHw_cmd_rsp$("NEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3)
4940            ELSE
4941              Temp$=FNHw_cmd_rsp$("SNEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3)
4942            END IF                              ! Use_main_ram
4943            IF FNHw_io_error THEN 
4944              Icode_exec_err("Icode_def_ext: I/O error on block allocation")
4945              RETURN -1
4946            ELSE
4947              Block_id=VAL(Temp$)
4948              IF Block_id=-1 THEN 
4949                Icode_exec_err("Icode_def_ext: HP-IB module won't allocate block")
4950                RETURN -1
4951              END IF
4952              Line$=Info$(Info_pos)
4953              IF Use_main_ram THEN 
4954                Line$[17;1]="3"
4955              ELSE
4956                Line$[17;1]="4"
4957              END IF
4958              IF Line$[17;1]="1" OR Line$[17;1]="2" THEN 
4959                Icode_exec_err("Icode_def_ext: Can't redefine auto allocate blocks")
4960                RETURN -1
4961              END IF
4962            END IF
4963          ELSE
4964            Line$=Info$(Info_pos)
4965            IF Line$[17;1]="1" OR Line$[17;1]="2" THEN 
4966              Icode_exec_err("Icode_def_ext: Can't redefine auto allocate blocks")
4967              RETURN -1
4968            ELSE
4969              IF Use_main_ram THEN 
4970                Line$[17;1]="3"
4971              ELSE
4972                Line$[17;1]="4"
4973              END IF
4974            END IF
4975          END IF                             ! IF Block_id<=0
4976          Line$[23,28]=VAL$(Block_size)
4977          Line$[29,34]=VAL$(Hblock_size)
4978          Line$[35,39]=VAL$(Block_id)
4979          Info$(Info_pos)=Line$
4980        END IF
4981        Info_pos=Info_pos+1
4982      END WHILE
4983      IF NOT Found_match THEN 
4984        Icode_exec_err("Icode_def_ext: Undefined Block_name - '"&Block_name$&"'")
4985        RETURN -1
4986      END IF
4987    ELSE
4988      Icode_exec_err("Icode_def_ext: "&Error_string$)
4989      RETURN -1
4990    END IF
4991    RETURN Block_id
4992  FNEND                   ! Icode_def_ext
4993  !
4994 Icode_inpt_num:SUB Icode_inpt_num(Prompt_string$,INTEGER Inpt_num,Null_flag,Error_flag,OPTIONAL Inpt_str$)
4995!
4996!   This subprogram is used by the debugger to enter an integer number.
4997!   The user is prompted with the string parameter Prompt_string$.  If the
4998!   user does not enter a string (just hit return), then Null_flag is set
4999!   true.  If an error occurs during input, then Error_flag is set true.
5000!   If the string entered by the user is not a valid decimal or hex number,
5001!   and the OPTIONAL parameter Inpt_str$ is present, then Inpt_str$ is
5002!   returns with the user input string.
5003!
5004    DIM Temp$[100]
5005    Error_flag=0
5006    Null_flag=0
5007    IF NPAR=5 THEN Inpt_str$=""
5008    DISP Prompt_string$;
5009    LINPUT "",Temp$
5010    Temp$=TRIM$(Temp$)
5011    IF Temp$="" THEN 
5012      Null_flag=1
5013    ELSE
5014      ON ERROR GOTO Icode_dbg_oops
5015      IF Temp$[1,1]="$" THEN 
5016        Inpt_num=DVAL(Temp$[2],16)
5017      ELSE
5018        Inpt_num=VAL(Temp$)
5019      END IF
5020      IF 0 THEN 
5021 Icode_dbg_oops:!
5022        IF NPAR=5 THEN 
5023          Inpt_str$=UPC$(TRIM$(Temp$))
5024          Error_flag=1
5025        ELSE
5026          Error_flag=1
5027          Inpt_num=0
5028          BEEP 
5029          DISP "***** Invalid numerical entry *****"
5030          WAIT 3
5031        END IF
5032      END IF
5033      OFF ERROR 
5034    END IF
5035  SUBEND
5036  !
5037 Icode_inpt_str:SUB Icode_inpt_str(Prompt_string$,Inpt_str$)
5038!
5039!   This subprogram is used to prompt the user and enter a string from the
5040!   user.  The user is prompted with Prompt_string$ and the caller is
5041!   returned Inpt_str$.
5042!
5043    DISP Prompt_string$;
5044    LINPUT "",Inpt_str$
5045    Inpt_str$=UPC$(TRIM$(Inpt_str$))
5046  SUBEND
5047  !
5048 Icode_asc_str:DEF FNIcode_asc_str$(INTEGER Sixteen_bit_num)
5049!
5050!   This function is used to convert a 16 bit integer into two characters.
5051!   The Hi and Lo order bits are each converted into their ascii
5052!   ascii representation.  An ascii representation of a control or non
5053!   printable character is replaces with a '.'.
5054!
5055    DIM Temp$[2]
5056    INTEGER Hi,Lo
5057    Hi=Sixteen_bit_num DIV 256
5058    Lo=Sixteen_bit_num MOD 256
5059    IF Hi>=32 AND Hi<=126 THEN 
5060      Temp$=CHR$(Hi)
5061    ELSE
5062      Temp$="."
5063    END IF
5064    IF Lo>=32 AND Lo<=126 THEN 
5065      Temp$[2]=CHR$(Lo)
5066    ELSE
5067      Temp$[2]="."
5068    END IF
5069    RETURN Temp$
5070  FNEND
5071 Lib_lib:SUB Lib_lib
5072   !************************************************************************
5073   !* This routine contains all the commons used in the all the library
5074   !* routines.  It is needed by the application loader to handle commons.
5075   !************************************************************************
5076    COM /Lib_c1_lbl_info/ Input_labels$(1:63)[20],Source_labels$(1:63)[20]
5077    COM /Lib_c1_overload/ INTEGER Ovld_buffer(1:63)
5078    COM /Lib_c1_blk_ids/ REAL Icode_id,Input_buffer_id,Module_list_id,Ovld_buffer_id
5079    COM /Lib_c1_inp_info/ REAL Num_inputs,INTEGER Block_size,Max_tdly_label$[20]
5080    COM /Lib_c1_src_info/ REAL Num_sources,Cal_src_label$[20]
5081    COM /Lib_c1_icode_cd/ Source$(0:100)[80],INTEGER Object(0:100)
5082    COM /Lib_c1_icode_fo/ Info$(0:20)[40]
5083    COM /Lib_c1_dft_coef/ REAL Dft_coef_real(0:255,1:20),Dft_coef_imag(0:255,1:20)
5084    COM /Lib_c1_cal_con/ REAL Calcon_real(1:63,1:20),Calcon_imag(1:63,1:20)
5085    COM /Lib_c1_harm_dat/ REAL Cal_harmonics(-1:20),INTEGER Num_harmonics,REAL Phase_ramp,Hz_per_harmonic
5086    COM /Lib_c1_first/ INTEGER Runned_yet
5087    COM /Lib_c1_cal_data/ REAL Error_mag(1:63,-1:20),Error_phase(1:63,-1:20),Mag_deriv(1:63,-1:20),Phase_deriv(1:63,-1:20),Freq(-1:20)
5088    COM /Lib_c1_error/ INTEGER Errored,No_c1_cal
5089   !
5090    SUBEXIT
5091  SUBEND
5092!
5093 Lib_float_to_64:SUB Lib_float_to_64(Float,INTEGER I1,I2,I3,I4)
5094  !
5095  !Converts an IEEE 64-bit floating point number
5096  ! into its 4 16-bit integers.  Used by the Icode Assembler
5097  !
5098    ASSIGN @Buff TO BUFFER [8];FORMAT OFF !8 bytes / fp word
5099    OUTPUT @Buff;Float
5100    ENTER @Buff;I1,I2,I3,I4
5101  SUBEND
5102  !
5103  ! PAGE ->
5104  !********************************************************************
5105 Lib_fft_coefs:SUB Lib_fft_coefs(INTEGER Coef_table(*))
5106  !
5107  ! This routine generates a 1/2 sine and 1/2 cos table in the
5108  !array Coef_table, for use by the default FFT algorithm supplied
5109  !in HP35651A ROM.
5110  !
5111    IF SIZE(Coef_table,1)<>4096 THEN CALL User_stop("Error in Lib_fft_coefs--FFT Coefficient array must be 4096 elements long")
5112    ON ERROR GOTO No_coef_file
5113    ASSIGN @Cfile TO FNLib_full_path$("FFT_COEFS");FORMAT OFF
5114    ENTER @Cfile;Coef_table(*)
5115    SUBEXIT
5116 No_coef_file:!
5117    DISP "Generating FFT coefficients  (could not find file), be patient"
5118    OFF ERROR 
5119    RAD
5120    Angle=2*PI/4096
5121    FOR I=0 TO 4095 STEP 2
5122      J=I/2
5123      Coef_table(I)=32767*COS(J*Angle)
5124      Coef_table(I+1)=32767*SIN(J*Angle)
5125    NEXT I
5126    DISP ""
5127  SUBEND
5128  !
5129  ! PAGE ->
5130  !********************************************************************
5131 Lib_sizeof:DEF FNLib_sizeof(INTEGER Array(*))
5132  !
5133  !This routine returns the total number of an elements in an integer
5134  ! array.  (Depends on SIZE and RANK)
5135  !
5136    Num_elements=1
5137    FOR I=1 TO RANK(Array)
5138      Num_elements=Num_elements*SIZE(Array,I)
5139    NEXT I
5140    RETURN Num_elements
5141  FNEND
5142  !
5143  ! PAGE ->
5144  !********************************************************************
5145 Lib_fsizeof:DEF FNLib_fsizeof(Array(*))
5146  !
5147  !This routine returns the total number of an elements in a floating point
5148  ! array.  (Depends on SIZE and RANK)
5149  !
5150    Num_elements=1
5151    FOR I=1 TO RANK(Array)
5152      Num_elements=Num_elements*SIZE(Array,I)
5153    NEXT I
5154    RETURN Num_elements
5155  FNEND
5156  !
5157  ! PAGE ->
5158  !********************************************************************
5159 Lib_full_path:DEF FNLib_full_path$(Filename$)
5160  ! This function tries to return the full path name of a file.
5161  ! Tries the filename itself first, then tries several combinations
5162  ! of prefixes and suffixes.  The end user will probably want to change
5163  ! these to path names suitable for his/her location.
5164  !
5165    DIM Try_path$[160]
5166    !
5167    DIM Prefix$(0:1)[80]
5168    DIM Suffix$(0:6)[80]
5169    !
5170    !change the next lines to appropriate prefixes
5171    Prefix$(0)=""   !the most likely prefix?
5172    Prefix$(1)=""   !yet another prefix
5173    !
5174    Suffix$(0)=""
5175    Suffix$(1)=":,702,0"
5176    Suffix$(2)=":,702,1"
5177    Suffix$(3)=":,703,0"
5178    Suffix$(4)=":,703,1"
5179    Suffix$(5)=":INTERNAL,4,0"
5180    Suffix$(6)=":INTERNAL,4,0"
5181    !
5182    FOR J=0 TO 6
5183      FOR I=0 TO 1
5184        Try_path$=Prefix$(I)&Filename$&Suffix$(J)
5185        ASSIGN @File TO Try_path$;RETURN Error_code
5186        SELECT Error_code
5187        CASE 0,58 !No error, Improper File Type: We found it
5188          RETURN Try_path$
5189        CASE 52,56,62,72,76,80,82,93 !Errors to ignore
5190        CASE ELSE
5191          User_error("***In Lib_full_path$: "&VAL$(Error_code)&" ***")
5192          RETURN ""
5193        END SELECT
5194      NEXT I
5195    NEXT J
5196    User_error("***Lib_full_path$: "&Filename$&" not found ***")
5197    RETURN ""
5198  FNEND
5199  !
5200  ! PAGE ->
5201  !************************************************************************
5202 Lib_32_to_16:SUB Lib_32_to_16(Val32bit,INTEGER Ihigh,Ilow)
5203 !
5204 ! Converts the floating point value in Val32bit (in range -2^31 to
5205 ! 2^31 - 1 ) to 2 integers: Ihigh with the upper 16 bits and Ilow
5206 ! with the lower 16 bits of the 2's complement representation.
5207 !
5208    Float_temp=Val32bit
5209    Neg=0
5210    IF Float_temp=0 THEN 
5211      Neg=1
5212      Float_temp=-Float_temp
5213      Float_temp=Float_temp-1
5214    END IF
5215    Ihigh=INT(Float_temp/65536)
5216    Float_temp=Float_temp-Ihigh*65536
5217    IF Float_temp>32767 THEN 
5218      Ilow=INT(Float_temp-32768)
5219      Ilow=BINEOR(Ilow,-32768)
5220    ELSE
5221      Ilow=Float_temp
5222    END IF
5223    IF Neg=1 THEN 
5224      Ihigh=BINCMP(Ihigh)
5225      Ilow=BINCMP(Ilow)
5226    END IF
5227  SUBEND
5228  !
5229  !***********************************************************************
5230  ! PAGE -> 
5231 User_error:SUB User_error(Aline$)
5232   !This subprogram reports errors to the user using the DISP line,
5233   !beeps, waits 3 sec, and exits.
5234    BEEP 100,.1
5235    DISP Aline$
5236    WAIT 3
5237    DISP 
5238  SUBEND
5239 !-------------------------------------------------------------------
5240 User_stop:SUB User_stop(Aline$)
5241   !This subprogram reports fatal program errors and PAUSEs the program.
5242   !The STEP key can be used to get back to the calling context.
5243    BEEP 100,.5
5244    DISP Aline$
5245    PAUSE
5246    DISP 
5247  SUBEND
5248 !-------------------------------------------------------------------