2! OUTPUT 2 USING "#,K";"<lf>INDENT<cr>RE-STORE ""ICODE""<cr>" 3 ! Rev 1.1: Fixed #3 in SUB Icode_debug. 5 ! 6 END 8 ! PAGE -> 10 !************************************************************************ 12 ! 14 Icode_icode:SUB Icode_icode 16 ! 18 ! This subroutine is used to initialize the ICODE file. As you can see 20 ! there is not much to initialize. 22 ! 24 SUBEND 26 ! 28 Icode_assemble:DEF FNIcode_assemble(Source$(*),INTEGER Object(*),INTEGER Info_info,Info$(*),INTEGER Enable_list_arg,List$(*)) 30 ! 32 ! 34 ! This subprogram 'Icode_assemble', is used to translate ICODE assembly 36 ! language programs into object code that can be run in the HP3565S HP-IB 38 ! module. The ICODE assembly language is defined in the ICODE section of 40 ! demo programs manual. 42 ! 44 ! ==> Assembler activation: 46 ! 48 ! Error_count=FNIcode_assemble(Source$(*),INTEGER Object(*) 50 ! INTEGER Info_info,Info$(*),INTEGER Enable_list_arg 52 ! List$(*)) 54 ! 56 ! Source$(*): Input - Holds ICODE source code. Each line of Source$ 58 ! contains one line of source code. Instructions 60 ! with large parameter list may use more than one 62 ! line by using a continuation line. The first 64 ! character of a continuation line must be a '.'. 66 ! The Source$ index must start at 0. 68 ! The length the string elements in Source$ is 70 ! defined by the user. 72 ! Assembly will start at the beginning of Source$ 74 ! and continue until the end of Source$ is found, 76 ! or until a line containing 'EL_COMPLETO' is 78 ! found. If 'EL_COMPLETO' is used to terminate 80 ! assembly, then Source$ is REDIMed to the actual 82 ! size of the source program. 84 ! Object(*): Output - Holds assembled ICODE object code. 86 ! The Object index must start at 0. 88 ! Object(*) is REDIMed to the size of the object 90 ! code. 92 ! Note that Info_info=2 will increase the size 94 ! object array by 1 element for each assembled 96 ! instruction. 98 ! Info_info: Input - Determines what information the assembler 100! should put in the Info$(*) array. 102! 0 - Info$(*) is not accessed. 104! 1 - Info$(*) is filled with information 106! to be used by 'Icode_dld', 'Icode_ext_id' 108! and 'Icode_def_ext'. 110! 2 - Info$(*) is filled with information as 112! if Info_info=1, and filled with info 114! to be used by the 'Icode_debug'. 116! Info_info=2 will also cause 'c_nop's to 118! be insert in between each instruction. 120! This is used by the debugger to set break 122! points. Note that this will increase the 124! size of the object code and also the size 126! of the listing output if enabled. 128! This mode may be used during program 130! development. 132! Info$(*): Output - Holds information to be used by other ICODE 134! file subprograms. 136! The Info$ index must start at 0. 138! If Info_info=0, then Info$(*) is unaffected. 140! If Info_info<>0 then Info$(*) string elements 142! must be 40 characters long. 144! If Info_info=1 then Info$(*) must have 6 lines 146! + one line for each DEFBLK_SP,DEFBLK_MAIN or 148! DEFBLK_EXT. 150! If Info_info=2 then Info$(*) must have as many 152! lines as in Info_info=1 + 4 + one line for each 154! DEFBLK_VAR, DEFBLK_CON, VAR, + one line for 156! each label, + one line for each 10 instructions. 158! Enable_list_arg: Input - If 0, then List$(*) will not be accessed. 160! If 1, then List$(*) will be filled with the 162! assembly listing. 164! List$(*): Output - Holds the assembly listing. 166! The number of elements and the length of each 168! string in List$ is defined by the user. 170! The List$ index must start at 0. 172! List$ string elements should be 15 chars 174! longer than the string elements in Source(*). 176! The number of elements in List$ should be 178! ABOUT 2 to 4 times the number of lines in 180! Source$(*). Note that Info_info=2 will cause 182! the assembler to insert 'c_nop's in between 184! each instruction. These 'c_nop's will show 186! up in List$. List$ will be REDIMed to the size 188! required to host the assembly listing 190! 192! ==> Example assembler activation: 194! 196! The following is an example of how the assemble an in line ICODE program. 198! 200! 110 Icode_program:! 202! 120 DATA " err_abrt_count 5" 204! 130 DATA " err_disp_lines 3" 206! 140 DATA " var loop_ptr 0 " 208! 150 DATA " const loop_max 10 ! loop 10 times" 210! 160 DATA " " 212! 170 DATA "loop_begin: f_signal loop_ptr 214! 180 DATA " v_add loop_ptr,loop_ptr,1 ! inc ptr" 216! 190 DATA " c_beq loop_begin loop_ptr " 218! 200 DATA ". loop_max " 220! 210 DATA " c_end " 222! 220 DATA "el_completo" 224! . 226! . 228! 500 DIM Source$(0:200)[80],List$(0:400)[120],Source_line$[80] 230! 510 INTEGER Object(0:300),Info_info,Enable_list,Prog_id,Error_count 232! . 234! 600 Source_ptr=-1 236! 610 RESTORE Icode_program 238! 620 REPEAT 240! 630 READ Source_line$ 242! 640 Source_ptr=source_ptr+1 244! 650 Source$(Source_ptr)=Source_line$ 246! 660 UNTIL Source_line="el_completo" 248! 670 ! 250! 680 Info_info=2 ! Enable auto allocate vars and debugger 252! 690 Enable_list=1 ! Enable listing 254! 700 ! 256! 710 Error_count=FNIcode_assemble(Source$(*),Object(*),Info_info,Info$(*) 258! Enable_list,List$(*)) 260! 720 IF Error_count<>0 THEN 262! 730 OUTPUT CRT; "Errors during assembly. Program paused" 264! 740 PAUSE 266! 750 END IF 268! 760 Prog_id=FNIcode_dld(Object(*),Info_info,Info$(*)) ! download prog 270! 770 IF Prog_id<=0 THEN 272! 780 OUTPUT CRT; "Couldn't download ICODE program. Program paused." 274! 790 PAUSE 276! 800 END IF 278! 810 FNHw_cmd("PROG "&Prog_id) ! start ICODE program 280! . 282! . 284! 286! ==> Listing format: (all values in Hex) 288! 290! OBJ ASM ASM SOURCE CODE 292! ADDR VALU VALU 294! 296! 0004 0000 0004 var loop_ptr 0 298! 000A const loop_max 10 ! loop 10 times 300! 302! 0006 003D <c_nop> 304! 0007 0012,FFFE loop_begin: f_signal loop_ptr ! send loop ptr 306! 0009 003D <c_nop> 308! 000A 0047,FFFE v_add loop_ptr,loop_ptr,1 ! inc ptr 310! 000C FFFE,0001 312! 000E 003D <c_nop> 314! 000F 0039,0000 c_beq loop_begin loop_ptr 316! 0011 0006,FFFE . loop_max 318! 0013 000A 320! 0014 003D <c_nop> 322! 0015 0030 c_end 324! 0016 003D <c_nop> 326! 328! The array List$ will be filled the the assembly listing if the input 330! parameter List_enable is non zero. The listing has the following format: 332! + The first column of the listing indicates the hex address into the 334! object array. 336! + The second and third columns are the data values inserted into the 338! Object array. 340! + The rest of the line is the source code 342! + Lines that contain <c_nop> are inserted by the assembler for use by 344! the debugger in setting break points. These <c_nop>s would not be e 346! if Info_info were equal to 0 or 1. 348! 350! ==> Source code format general: 352! 354! The source code passed to the assembler through Source$(*) has two 356! sections. The first section is the pseudo-op section, and the second 358! section is the main assembly section. Most of the syntax is similar 360! to that of a standard assembler. Some global notes follow: 362! + All parameter fields that require a numerical field may be in 364! decimal or in hex. Hex numbers are specified by a "$" directly 366! before the hex number. 368! + All characters after the first occurrence of an '!' on any line 370! will be treated as comments. 372! + Parameter list elements may be delimited by either a space or by 374! a comma. Between the opcode and the parameter list must be a 376! space. 378! + This is a one pass assembler. Labels are the only type of symbol 380! that may be referenced before the symbol is defined. 382! + Once a CONST has been defined, the CONST symbol may be used any 384! place a numerical field is used. 386! + All symbols may be up to 16 characters long and are case 388! insensitive. The first character in a symbol must be a letter. 390! The rest should be letters, numbers or an underscore. Other 392! characters may not generate an error. User beware. 394! + Symbols may be larger than 16 characters but only the first 16 396! are significant. It would be best to make sure that all symbols 398! are <= 16 characters in length. 400! + ***** NOTE: When a new symbol is defined (Variable name, ***** 402! ***** Block name, etc ), NO checking is done to make ***** 404! ***** sure that the symbol is not already defined. ***** 406! ***** When a reference is made to a duplicate symbol,***** 408! ***** it is undefined as to which one will be ***** 410! ***** referenced. ***** 412! + Below is a list of characters with special meaning. 414! - '$' used to indicate a hex number. 416! - '^' used to reference a header block. 418! - '@' used to reference a variable through indirection. 420! - ':' used as a label terminator. 422! - ''' used to delimit a string parameter. 424! - '!' used to indicate the beginning of a comment. 426! - ',' used to delimit two parameters. 428! - '.' used to indicate a continuation line. 430! 432! 434! ==> Pseudo-op section: 436! 438! The pseudo-op section of a program begins at the beginning of Source(*) 440! and continues until the end-of-program is found or until the first main 442! assembly instruction is found. Below is a description of each pseudo-op 444! pseudo-op. 446! 448! 450! ERR_ABRT_COUNT <error count> 452! 454! This pseudo-op is used to tell the assembler how many errors should 456! cause the assembler to stop assembling. By default, this value is 458! four. 460! 462! ERR_DISP_LINES <# lines to disp before error> 464! 466! This pseudo-op is used to tell the assembler how many source lines 468! before an instruction with an error should be displayed on the CRT. 470! By default, this value is two. 472! 474! VAR <variable_name> <init value> 476! 478! This pseudo-op is used to define and initialize an ICODE variable. 480! The <init value> field may be a CONST only if the constant has 482! already been defined. To initialize one variable to the variable 484! number of another variable (which must already be defined) do as 486! follows: 488! 490! 20 DATA " var first_var 100 " 492! 30 DATA " var second_var @first_var" 494! 496! In the above example, if 'first_var' is variable number 5, then 498! 'second_var' will be initialized to 5. Note that 'first_var' must 500! be defined before it may be used to initialize another variable. 502! This may be useful if indirect variable accesses are being used. 504! 506! 508! CONST <const name> <const value> 510! 512! This pseudo-op is used to define a constant. A constant symbol may 514! be used any place an immediate parameter (floating point or integer) 516! can be used once the CONST has been defined. If the constant is 518! given a floating point value, and is used is a place that requires 520! an integer (most of the time), the value used is INT(const_val). 522! i.e. the floating point number is truncated. 524! 526! DEFBLK_CON <block_name> <block_id> 528! 530! This pseudo-op is used to define a block id if the block id is known 532! at assembly time. 534! 536! DEFBLK_VAR <block_name> <block_id_var_init_value> 538! 540! This pseudo-op is used to define a block id where the block id will be 542! put in a variable. An init value must be specified even though the 544! variable need not contain the actual block id until runtime. 546! 548! DEFBLK_EXT <block_name> 550! 552 ! This pseudo-op is used to define a block name symbol within the ICODE 554! program, but let the actual binding of the block name to the block id 556! be done external to the assembly process. To bind a block id to the 558! block symbol, the function 'FNIcode_def_ext' need be used. This may 560! be useful if the block type (MAIN or SP) or size is not known at 562! assembly time. This is also useful if multiple ICODE programs wish 564! to share the same block. Through the used of 'FNIcode_def_ext', the 566! user may allocate their own block and then bind it to <block_name> or 568! tell 'FNIcode_def_ext' the block type and size, and have 'FNIcode_dld' 570! allocate the block at runtime. To access the header block that may be 572! associated with <block_name> a 'hat' may be placed in from of the 574! <block_name> in the ICODE program. i.e. ^fft_blk_name 576! 578! DEFBLK_SP <block_name> <blk_size> <hblk_size> 580! 582! This pseudo-op is used to define an HP-IB module SP data RAM block 584 ! for the assembly process and have the downloader allocate the block 586 ! at runtime. For assembly, only the block size and the header block 588 ! size need be known. 'FNIcode_dld' will allocate and bind the correct 590 ! block id to <block_name>. To access the header block that may be 592 ! associated with <block_name> a 'hat' may be placed in from of the 594 ! <block_name> in the ICODE program. i.e. ^fft_blk_name 596 ! 598 ! DEFBLK_MAIN <block_name> <blk_size> <hblk_size> 600 ! 602 ! This pseudo-op is used to define an HP-IB module MAIN data RAM block 604 ! for the assembly process and have the downloader allocate the block 606 ! at runtime. For assembly, only the block size and the header block 608 ! size need be known. 'FNIcode_dld' will allocate and bind the correct 610 ! block id to <block_name>. To access the header block that may be 612 ! associated with <block_name> a 'hat' may be placed in front of the 614 ! <block_name> in the ICODE program. i.e. ^fft_blk_name 616 ! 618 ! LBL_TBL_SIZE <label_table_size> 620 ! 622 ! This pseudo-op is used to define the size of the label table size. 624 ! When the assembler comes across a label definition, its name and 626 ! location are placed in this table. Therefore, the label table must 628 ! have one entry for each label in the ICODE program. By default, 630 ! the label table has 50 entries. 632 ! 634 ! FORLBL_TBL_SIZE <forward_label_table_size> 636! 638 ! This pseudo-op is used to define the size of the forward reference 640 ! label table. When the assembler comes across a label reference to 642 ! a label that has not been defined yet, an entry is made in this 644 ! table. Note that there may be more than one entry for a single 646 ! label definition. When the label is defined, entry(s) referring 648 ! to the defined label are removed. Since the size of this table 650 ! is not a function of the number of labels, but rather the number 652 ! of undefined forward references outstanding at one time, it is 654 ! a little harder to choose the correct table size. By default, the 656 ! forward reference label table has 100 entries. 658! 660 ! ==> Main assembly section: 662! 664 ! This is the section of the ICODE program that contain the executable 666 ! instructions defined in the HP3565S ICODE manual. The syntax is 668 ! similar to that of a 'normal' assembler. Some general rules are as 670 ! follows: 672 ! + Each instruction must begin on a new line. Instructions with 674 ! parameter lists that require more than one line may use 676 ! continuation lines. A continuation line must have a '.' as 678 ! the first character on that line. Continuation across symbol 680 ! boundaries is not allowed. 682 ! + Too define a label, the label must be the first symbol on the 684 ! line. The label is terminated with an ':'. More than one 686 ! label may be used to point to one place in the ICODE program, 688 ! but each label must be on a separate line. 690 ! + Between the opcode and the parameter list must be a space. 692 ! No comma. 694 ! + Between the parameter list elements may be commas or spaces. 696 ! + Below is some example ICODE source code. This code is NOT 698 ! meant to mean anything program wise. It is meant to show 700 ! some of the basic constructs used in ICODE instructions. 702 ! 704 ! 210 DATA "label1: f_signal first_variable ! this is a comment " 706 ! 220 DATA " f_sync " 708 ! 230 DATA "label2: ! label2 and label3 are equivalent" 710 ! 240 DATA "label3: v_add loop_ptr loop_ptr 1 " 712 ! 250 DATA " c_beq exit_prog,loop_ptr,10 " 714 ! 260 DATA " v_mult loop_index ! " 716 ! 270 DATA ". loop_ptr 10 !this is a continuation line" 718 ! 370 DATA " c_goto label1 " 720 ! 722 ! + The HP3565S ICODE documentation says that a string parameter 724 ! is preceeded by the length of the string. To specify a string 726 ! parameter, the string need only be enclosed in single quotes 728 ! '''. The assembler will deal with the length field. 730 ! + If it is desired to enter immediate data into the ICODE 732 ! program, then the ASM_OFF directive may be used. The ASM_OFF 734 ! directive is of the form: 736 ! 738 ! ASM_OFF <parm_count> <parm1>,...,<parmn> 740 ! 742 ! <parm_count> is used to specify how many parameters follow. 744 ! Each parameter is evaluated (immediate, variable, or const) 746 ! and placed in the object array. The ASM_OFF directive may 748 ! not be embedded in another instructions parameter list. 750 ! 752 Icode_asm_start: ! 754 DIM Line$[255],Opcode$[20],Label$[20],Disp_line$[100],Version$[10] 756 DIM Arg$[20],Variable$[20],Inst_info$[255] 758 INTEGER Asm_loop_done,Def_loop_done,Line_ptr,I,J,K,Enable_list 760 REAL Real_temp,Arg,Max_32_int,Min_32_int,Max_16_int,Min_16_int 762 INTEGER Int_temp,Int_hi,Int_lo,Add_object 764 INTEGER Source_last,Object_last 766 INTEGER Old_forlbl_last 768 INTEGER Info_inst_base,Info_inst_cnt,Inst_cnt 770 DIM Error_string$[100],Block_name$[20] 772 DIM Repeat_str$[512] 774 ! 776 ! Let's do some initialization 778 ! 780 Icode_version: ! 782 Version$="1.0" 784 Disp_line$="ICODE Assembler version "&Version$&" " 786 DISP Disp_line$;" Initializing." 788 ! 790 Source_size=SIZE(Source$,1) 792 Object_size=SIZE(Object,1) 794 Info_size=SIZE(Info$,1) 796 List_size=SIZE(List$,1) 798 ! 800 Lbl_tbl_size=50 ! default label table size 802 Forlbl_tbl_size=100 ! default forward reference label tbl size 804 Err_abrt_count=4 ! default error count to abort assembly 806 Err_disp_lines=2 ! default # lines to disp when error is found 808 ! 810 Error_count=0 812 Missing_arg=0 814 ! 816 ! Init table pointers. Pointers point to last entry used. 818 Last_alloc_var=1 ! first var allocated will be var 2 820 Vars_allocated=0 822 Source_last=-1 824 Object_last=-1 826 Old_object_last=-1 828 List_last=-1 830 ! 832 Max_32_int=(2^31)-1 834 Min_32_int=-(2^31) 836 Max_16_int=(2^15)-1 838 Min_16_int=-(2^15) 840 ! 842 MAT List$= ("") 844 MAT Info$= ("") 846 ! 848 ! Check out parameter arrays to see if they are indexed correctly 850 ! 852 IF BASE(Object,1)<>0 THEN 854 Error_string$="Object(*) index must start at zero" 856 GOSUB Icode_init_err 858 END IF 860 IF BASE(Source$,1)<>0 THEN 862 Error_string$="Source(*) index must start at zero" 864 GOSUB Icode_init_err 866 END IF 868 IF Enable_list_arg THEN 870 IF BASE(List$,1)<>0 THEN 872 Error_string$="Listing array index must start at zero" 874 GOSUB Icode_init_err 876 END IF 878 ON ERROR GOTO Icode_list_lerr !List$(*) must be at least 80 chars wide 880 List$(0)=RPT$(" ",80) ! Even though List$ elements have 80 882 List$(0)="" ! chars doesn't mean that they are 884 IF 0 THEN ! large enough. 886 Icode_list_lerr:OFF ERROR 888 Error_string$="List$(*) elements should be GREATER than 80 chars" 890 Enable_list=0 892 GOSUB Icode_init_err 894 END IF 896 END IF 898 ! 900 GOSUB Icode_chk_info ! Check Info$(*) for correct dimensions 902 ! 904 ! Do Pre-pass. Go through pseudo-op section of ICODE program and 906 ! find out how large tables must be. 908 ! 910 Var_tbl_size=0 912 Blkvar_tbl_size=0 914 Blkext_tbl_size=0 916 Blkcon_tbl_size=0 918 Const_tbl_size=0 920 ! 922 DISP Disp_line$;" Doing Pre-pass." 924 Icode_def_loop: ! Pre-pass: Just get table size info 926 Enable_list=0 ! Disable listing for pre-pass. 928 Def_loop_done=0 930 REPEAT 932 GOSUB Icode_next_line 934 GOSUB Icode_skip_lbl 936 GOSUB Icode_get_opcod 938 GOSUB Icode_init_inst 940 SELECT Opcode$ 942 CASE "VAR" 944 Var_tbl_size=Var_tbl_size+1 946 CASE "DEFBLK_VAR" 948 Blkvar_tbl_size=Blkvar_tbl_size+1 950 CASE "DEFBLK_SP","DEFBLK_MAIN","DEFBLK_EXT" 952 Blkext_tbl_size=Blkext_tbl_size+2 954 CASE "DEFBLK_CON" 956 Blkcon_tbl_size=Blkcon_tbl_size+1 958 CASE "CONST" 960 Const_tbl_size=Const_tbl_size+1 962 CASE "DEF_END" 964 Def_loop_done=1 966 CASE "LBL_TBL_SIZE" 968 Enable_const=1 970 GOSUB Icode_get_arg 972 IF Missing_arg THEN 974 Error_string$="Missing LBL_TBL_SIZE parameter" 976 GOSUB Icode_err 978 ELSE 980 IF Arg>0 AND Arg<32767 THEN 982 Lbl_tbl_size=Arg 984 ELSE 986 Error_string$="Invalid LBL_TBL_SIZE specification - '"&VAL$(Arg)&"'" 988 GOSUB Icode_err 990 END IF 992 END IF 994 CASE "FORLBL_TBL_SIZE" 996 Enable_const=1 998 GOSUB Icode_get_arg 1000 IF Missing_arg THEN 1002 Error_string$="Missing FORLBL_TBL_SIZE parameter" 1004 GOSUB Icode_err 1006 ELSE 1008 IF Arg>0 AND Arg<32767 THEN 1010 Forlbl_tbl_size=Arg 1012 ELSE 1014 Error_string$="Invalid FORLBL_TBL_SIZE specification - '"&VAL$(Arg)&"'" 1016 GOSUB Icode_err 1018 END IF 1020 END IF 1022 CASE "ERR_ABRT_COUNT" 1024 Enable_const=1 1026 GOSUB Icode_get_arg 1028 IF Missing_arg THEN 1030 Error_string$="Missing ERR_ABRT_COUNT parameter" 1032 GOSUB Icode_err 1034 ELSE 1036 IF Arg>0 AND Arg<1000 THEN 1038 Err_abrt_count=Arg 1040 ELSE 1042 Error_string$="Invalid ERR_ABRT_COUNT specification - '"&VAL$(Arg)&"'" 1044 GOSUB Icode_err 1046 END IF 1048 END IF 1050 CASE "ERR_DISP_LINES" 1052 Enable_const=1 1054 GOSUB Icode_get_arg 1056 IF Missing_arg THEN 1058 Error_string$="Missing ERR_DISP_LINES parameter" 1060 GOSUB Icode_err 1062 ELSE 1064 IF Arg>=0 AND Arg<100 THEN 1066 Err_disp_lines=Arg 1068 ELSE 1070 Error_string$="Invalid ERR_DISP_LINES specification - '"&VAL$(Arg)&"'" 1072 GOSUB Icode_err 1074 END IF 1076 END IF 1078 CASE ELSE 1080 CALL Icode_inst_str(Opcode$,Inst_info$) 1082 IF Inst_info$<>"-1" OR Opcode$="EL_COMPLETO" THEN Def_loop_done=1 1084 END SELECT 1086 GOSUB Icode_next_inst 1088 UNTIL Def_loop_done 1090 ! 1092 Enable_list=Enable_list_arg ! Enable listing of so desired 1094 ! 1096 GOSUB Icode_alloc_tbl ! Allocate all internal tables 1098 ! 1100 Source_last=-1 ! reset pointer into source array 1102 List_last=-1 ! and listing array 1104 ! 1106 ! Allocate variable space. Variable space needs to be allocated 1108 ! for all VAR, DEFBLK_VAR, DEFBLK_SP, DEFBLK_MAIN, and DEFBLK_EXT 1110 ! pseudo-ops. Don't forget, variables start at 2. 1112 DISP Disp_line$;" Allocating variable space." 1114 Icode_alloc_var:! 1116 Vars_allocated=Var_tbl_size+Blkvar_tbl_size+Blkext_tbl_size+2 1118 IF Vars_allocated<>0 THEN ! allocate room in ICODE prog for vars 1120 Object(0)=49 ! insert c_goto around variable space 1122 Object(1)=0 ! programs can't be greater than 32K 1124 Real_temp=Vars_allocated*2 1126 IF Real_temp>=Object_size THEN 1128 Error_string$="Object code array too small for required variable space" 1130 GOSUB Icode_fatal_err 1132 END IF 1134 Object(2)=Real_temp 1136 FOR I=3 TO Real_temp-1 ! Set all vars to 0. Dont' really need 1138 Object(I)=0 ! to do this. 1140 NEXT I 1142 Object_last=Real_temp-1 1144 END IF 1146 ! 1148 ! Insert listing header into List$(*) 1150 ! 1152 IF Enable_list THEN 1154 List_last=List_last+1 1156 IF List_last<List_size THEN 1158 ON ERROR GOTO Icode_list_len 1160 List$(List_last)="ICODE Assembler version "&Version$&". Assembled "&DATE$(TIMEDATE)&" "&TIME$(TIMEDATE) 1162 OFF ERROR 1164 IF 0 THEN 1166 Icode_list_len:OFF ERROR 1168 Error_string$="Listing lines need to be longer" 1170 Enable_list=0 1172 GOSUB Icode_fatal_err 1174 END IF 1176 ELSE 1178 Error_string$="Listing table overflow" 1180 GOSUB Icode_fatal_err 1182 END IF 1184 END IF 1186 ! 1188 IF Info_info=2 THEN 1190 ! 1192 ! For each instruction, an entry is made into Info$(*). Each entry 1194 ! consists of the address of the opcode and the source$(*) line 1196 ! index. Only need for the debugger. i.e. Info_info=2 1198 ! 1200 Info_inst_base=Info_hdr_size 1202 Inst_cnt=0 1204 END IF 1206 ! 1208 IF Enable_list_arg THEN 1210 DISP Disp_line$;" Assembling. Listing Enabled" 1212 ELSE 1214 DISP Disp_line$;" Assembling." 1216 END IF 1218 ! 1220 ! This loop assembles the pseudo-op section of the ICODE program. 1222 ! This loop is terminated when a non-pseudo-op instruction is 1224 ! found. 1226 ! 1228 Icode_tbl_loop:! 1230 Tbl_loop_done=0 1232 REPEAT 1234 GOSUB Icode_next_line ! find next instruction 1236 GOSUB Icode_skip_lbl ! don't really want to look at labels 1238 GOSUB Icode_get_opcod ! get Opcode$ 1240 GOSUB Icode_init_inst ! Init ptrs for listing and errs 1242 SELECT Opcode$ 1244 Icode_var:! 1246 CASE "VAR" 1248 Enable_const=0 ! Variable name may not be a CONST 1250 GOSUB Icode_get_arg ! returns Arg$, Arg, and Missing_arg 1252 IF Missing_arg OR Arg$="" THEN 1254 Error_string$="Missing variable name" 1256 GOSUB Icode_err 1258 ELSE 1260 Variable$=Arg$ 1262 Enable_const=1 ! Init value may be a CONST 1264 GOSUB Icode_get_arg 1266 IF Missing_arg THEN 1268 Error_string$="Missing or invalid variable init value" 1270 GOSUB Icode_err 1272 ELSE 1274 IF Arg>Max_32_int OR Arg<Min_32_int THEN 1276 Error_string$="Invalid variable init value - '"&VAL$(Arg)&"'" 1278 GOSUB Icode_err 1280 ELSE 1282 IF Arg$[1;1]="@" THEN ! Is init val another variables var number 1284 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2]) 1286 IF Var_pos=-1 THEN 1288 Error_string$="Undefined variable reference - '"&Arg$[2]&"'" 1290 GOSUB Icode_err 1292 ELSE 1294 Arg=Var_num(Var_pos) 1296 END IF 1298 ELSE 1300 IF Arg$<>"" THEN 1302 Error_string$="Invalid variable init value - '"&Arg$&"'" 1304 GOSUB Icode_err 1306 END IF 1308 END IF 1310 END IF 1312 END IF 1314 IF Error_string$="" THEN 1316 Var_last=Var_last+1 1318 Last_alloc_var=Last_alloc_var+1 1320 Var_name$(Var_last)=Variable$ 1322 Var_num(Var_last)=Last_alloc_var 1324 Lib_32_to_16(Arg,Int_hi,Int_lo) 1326 Object(Last_alloc_var*2)=Int_hi 1328 Object(Last_alloc_var*2+1)=Int_lo 1330 IF Enable_list THEN 1332 List$(Old_list_last)[1;15]=IVAL$(Last_alloc_var*2,16)&" "&IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16) 1334 END IF 1336 END IF 1338 END IF 1340 Defblk_var:! 1342 CASE "DEFBLK_VAR" 1344 Enable_const=0 ! Block name may not be a CONST 1346 GOSUB Icode_get_arg ! returns Arg$, Arg and Missing_arg 1348 IF Missing_arg OR LEN(Arg$)=0 THEN 1350 Error_string$="Missing DEFBLK_VAR block name" 1352 GOSUB Icode_err 1354 ELSE 1356 Block_name$=Arg$ 1358 Enable_const=1 ! Init value may be a CONST 1360 GOSUB Icode_get_arg 1362 IF Missing_arg OR Arg$<>"" THEN 1364 Error_string$="Missing or invalid DEFBLK_VAR init value" 1366 GOSUB Icode_err 1368 ELSE 1370 IF Arg>Max_32_int OR Arg<Min_32_int THEN 1372 Error_string$="Invalid DEFBLK_VAR init value - '"&VAL$(Arg)&"'" 1374 GOSUB Icode_err 1376 ELSE 1378 Blkvar_last=Blkvar_last+1 1380 Last_alloc_var=Last_alloc_var+1 1382 Blkvar_name$(Blkvar_last)=Block_name$ 1384 Blkvar_id(Blkvar_last)=Last_alloc_var 1386 CALL Lib_32_to_16(Arg,Int_hi,Int_lo) 1388 Object(Last_alloc_var*2)=Int_hi 1390 Object(Last_alloc_var*2+1)=Int_lo 1392 IF Enable_list THEN 1394 List$(List_last)[1;15]=IVAL$(Last_alloc_var*2,16)&" "&IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16) 1396 END IF 1398 END IF 1400 END IF 1402 END IF 1404 ! 1406 Defblk_con:! 1408 CASE "DEFBLK_CON" 1410 Enable_const=0 ! Block_name may not be a CONST 1412 GOSUB Icode_get_arg ! returns Token$ and Error_flag 1414 IF Missing_arg OR LEN(Arg$)=0 THEN 1416 Error_string$="Missing DEFBLK_CON block name" 1418 GOSUB Icode_err 1420 ELSE 1422 Block_name$=Arg$ 1424 Enable_const=1 ! block_id may be a CONST 1426 GOSUB Icode_get_arg 1428 IF Missing_arg OR Arg$<>"" THEN 1430 Error_string$="Missing or invalid DEFBLK_CON constant value" 1432 GOSUB Icode_err 1434 ELSE 1436 IF (Arg<=0 OR Arg>=32768) THEN 1438 Error_string$="Illegal DEFBLK_CON init value" 1440 GOSUB Icode_err 1442 ELSE 1444 IF Error_string$="" THEN 1446 Blkcon_last=Blkcon_last+1 1448 Blkcon_name$(Blkcon_last)=Block_name$ 1450 Blkcon_id(Blkcon_last)=Arg 1452 IF Enable_list THEN List$(Old_list_last)[6;4]=IVAL$((Arg),16) 1454 END IF 1456 END IF 1458 END IF 1460 END IF 1462 ! 1464 Defblk_main:! 1466 Defblk_sp:! 1468 CASE "DEFBLK_SP","DEFBLK_MAIN" 1470 IF Info_info=0 THEN 1472 Error_string$="Can't use "&Opcode$&" without Info$ array" 1474 GOSUB Icode_err 1476 ELSE 1478 Block_type=1 1480 IF Opcode$[8]="SP" THEN Block_type=2 1482 Enable_const=0 ! Block_name may not be a CONST 1484 GOSUB Icode_get_arg ! returns Arg$, Arg, and Missing_arg 1486 IF Missing_arg OR LEN(Arg$)=0 THEN 1488 Error_string$="Missing "&Opcode$&" block name" 1490 GOSUB Icode_err 1492 ELSE 1494 Block_name$=Arg$ 1496 Enable_const=1 ! block_size may be a CONST 1498 GOSUB Icode_get_arg 1500 IF Missing_arg OR Arg$<>"" OR Arg<=0 OR Arg>Max_32_int THEN 1502 Error_string$="Missing or invalid "&Opcode$&" block size" 1504 GOSUB Icode_err 1506 ELSE 1508 Block_size=Arg 1510 Blkext_last=Blkext_last+1 1512 Last_alloc_var=Last_alloc_var+2 1514 Enable_const=1 ! header_block_size may be a CONST 1516 GOSUB Icode_get_arg 1518 IF Missing_arg OR Arg$<>"" OR Arg<0 THEN 1520 Error_string$="Missing or invalid "&Opcode$&" header size" 1522 GOSUB Icode_err 1524 ELSE 1526 Header_size=Arg 1528 END IF 1530 Blkext_name$(Blkext_last)=Block_name$ 1532 Blkext_id(Blkext_last)=(Last_alloc_var-1) 1534 Blkext_type(Blkext_last)=Block_type 1536 Blkext_size(Blkext_last)=Block_size 1538 Blkext_hsize(Blkext_last)=Header_size 1540 IF Enable_list THEN 1542 List$(Old_list_last)[1;14]=IVAL$((Last_alloc_var-1)*2,16)&" ****,****" 1544 END IF 1546 END IF 1548 END IF 1550 END IF 1552 ! 1554 Defblk_ext:! 1556 CASE "DEFBLK_EXT" 1558 Enable_const=0 ! block_name may not be a CONST 1560 GOSUB Icode_get_arg ! returns Arg$, Arg, and Missing_arg 1562 IF Missing_arg OR LEN(Arg$)=0 THEN 1564 Error_string$="Missing DEFBLK_EXT block name" 1566 GOSUB Icode_err 1568 ELSE 1570 Blkext_last=Blkext_last+1 1572 Last_alloc_var=Last_alloc_var+2 1574 Blkext_name$(Blkext_last)=Arg$ 1576 Blkext_id(Blkext_last)=(Last_alloc_var-1) 1578 Blkext_type(Blkext_last)=0 1580 Blkext_size(Blkext_last)=-1 1582 Blkext_hsize(Blkext_last)=-1 1584 IF Enable_list THEN 1586 List$(Old_list_last)[1;14]=IVAL$((Last_alloc_var-1)*2,16)&" ****,****" 1588 END IF 1590 END IF 1592 ! 1594 Const:! 1596 CASE "CONST" 1598 DIM Constant_name$[16] 1600 Enable_const=0 ! New CONST_name may not be a CONST 1602 GOSUB Icode_get_arg ! returns Arg$, Arg, and Missing_arg 1604 IF Missing_arg OR LEN(Arg$)=0 THEN 1606 Error_string$="Missing CONST constant name" 1608 GOSUB Icode_err 1610 ELSE 1612 Constant_name$=Arg$ 1614 Enable_const=1 ! CONST value may be a CONST 1616 GOSUB Icode_get_arg 1618 IF Missing_arg OR LEN(Arg$)<>0 OR Arg<Min_32_int OR Arg>Max_32_int THEN 1620 Error_string$="Missing or invalid CONST constant value" 1622 GOSUB Icode_err 1624 ELSE 1626 Const_last=Const_last+1 1628 Const_name$(Const_last)=Constant_name$ 1630 Const_val(Const_last)=Arg 1632 IF Enable_list THEN 1633 Lib_32_to_16(Arg,Int_hi,Int_lo) 1634 List$(Old_list_last)[6;9]=IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16) 1635 END IF 1637 END IF 1638 END IF 1639 CASE "ERR_ABRT_COUNT","ERR_DISP_LINES","LBL_TBL_SIZE","FORLBL_TBL_SIZE" 1640 GOSUB Icode_get_arg ! This is a dummy get arg 1642 CASE "DEF_END" 1644 Tbl_loop_done=1 1646 CASE ELSE 1648 CALL Icode_inst_str(Opcode$,Inst_info$) 1650 IF Inst_info$<>"-1" OR Opcode$="EL_COMPLETO" OR Opcode$="ASM_OFF" THEN 1652 Tbl_loop_done=1 1654 GOSUB Icode_back_line 1656 ELSE 1658 IF POS(Opcode$,",")<>0 THEN 1660 Error_string$="Unexpected comma - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'" 1662 ELSE 1664 Error_string$="Undefined pseudo-op - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'" 1666 END IF 1668 Enable_list=0 1670 GOSUB Icode_fatal_err 1672 END IF 1674 END SELECT 1676 IF Error_string$="" AND Line$<>"" AND NOT Tbl_loop_done THEN 1678 Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'" 1680 GOSUB Icode_err 1682 END IF 1684 Here:! 1686 Error_string$="" 1688 UNTIL Tbl_loop_done 1690 ! 1692 ! This is the main assembly loop 1694 ! 1696 Icode_asm_loop:! 1698 Asm_loop_done=0 1700 REPEAT 1702 Error_string$="" 1704 ! 1706 GOSUB Icode_next_line 1708 ! 1710 IF Line$="EL_COMPLETO" THEN 1712 Asm_loop_done=1 1714 ELSE 1716 ! 1718 IF Info_info=2 THEN GOSUB Icode_insrt_nop 1720 ! 1722 IF Line$[1;1]="." THEN 1724 Error_string$="Not expecting continuation line" 1726 GOSUB Icode_err 1728 ELSE 1730 GOSUB Icode_check_lbl ! check for line label 1732 GOSUB Icode_get_opcod ! returns Opcode$ 1734 GOSUB Icode_init_inst ! init ptrs for listing and errs 1736 ! 1738 ! Get information about instruction. Opcode and parameters. 1740 ! 1742 CALL Icode_inst_str(Opcode$,Inst_info$) 1744 Opcode_num=VAL(Inst_info$) 1746 ! 1748 IF Opcode_num=-1 THEN 1750 IF Opcode$="ASM_OFF" THEN 1752 IF Info_info=2 THEN GOSUB Icode_info_isrt 1754 GOSUB Icode_asm_off 1756 GOSUB Icode_end_inst 1758 IF Error_string$="" AND Line$<>"" THEN 1760 Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'" 1762 GOSUB Icode_err 1764 END IF 1766 ELSE 1768 Error_string$="Undefined Opcode - '"&Opcode$[1,MIN(20,LEN(Opcode$))]&"'" 1770 GOSUB Icode_err 1772 END IF 1774 END IF 1776 ! 1778 IF Opcode_num<>-1 THEN 1780 Add_object=Opcode_num ! add opcode to object array 1782 GOSUB Icode_add_obj 1784 ! 1786 ! Put address of opcode and source line # into Info$(*). 1788 ! 1790 IF Info_info=2 THEN GOSUB Icode_info_isrt 1792 ! 1794 IF Error_string$="" THEN 1796 Inst_info_ptr=POS(Inst_info$," ") ! skip opcode field 1798 IF Inst_info_ptr<>0 THEN 1800 REPEAT 1802 Inst_info_ptr=Inst_info_ptr+1 ! look at next parm char 1804 SELECT Inst_info$[Inst_info_ptr;1] 1806 CASE "L" ! Label 1808 GOSUB Icode_get_label 1810 CASE "P" 1812 GOSUB Icode_get_param ! 16 bit immediate integer 1814 CASE "B" ! CONST or VAR 1816 GOSUB Icode_get_block ! DEFBLK_xxxx 1818 CASE "V" 1820 GOSUB Icode_get_var 1822 CASE "I" ! 32 bit immediate integer 1824 GOSUB Icode_get_int ! or CONST 1826 CASE "S" ! 'String' 1828 GOSUB Icode_get_str 1830 CASE "F" ! Floating point 1832 GOSUB Icode_get_float 1834 CASE "M" ! 16 bit immediate integer 1836 GOSUB Icode_get_immed 1838 CASE "R" ! Instruction has a repeating 1840 GOSUB Icode_rpt_str ! field. 1842 CASE "@" ! Instruction has more than one 1844 GOSUB Icode_mlty_inst ! form depending on last field. 1846 END SELECT 1848 UNTIL Inst_info_ptr=LEN(Inst_info$) 1850 ! 1852 IF Error_string$="" AND Line$<>"" THEN 1854 Error_string$="Extraneous argument - '"&Line$[1,MIN(20,LEN(Line$))]&"'" 1856 GOSUB Icode_err 1858 END IF 1860 END IF 1862 END IF 1864 GOSUB Icode_end_inst 1866 END IF ! If Opcode_num<>-1 1868 END IF 1870 END IF 1872 UNTIL Asm_loop_done 1874 ! 1876 ! See if there are any unresolved forward references. 1878 ! 1880 GOSUB Icode_forlbl_ck 1882 ! 1884 Object_last=Object_last+1 ! HP-IB module needs extra word in prog block 1886 ! 1888 GOSUB Icode_fill_info ! Fill Info$(*) with tons of stuff 1890 GOSUB Icode_asm_exit ! Final clean up and exit 1892 ! 1894 ! ************ Assembler GOSUB Subroutines *********************** 1896 ! 1898 Icode_subs:! 1900 IF 0 THEN 1902 ! 1904 ! This subroutine is used to repeat a section of the instruction info 1906 ! string. The substring between the parameter code 'R' and the next 1908 ! '!' is repeated <count> times. <count> is specified by the last 1910 ! 16 bit value places in the object array. 1912 ! 1914 Icode_rpt_str:! 1916 Repeat_count=Object(Object_last) 1918 IF Repeat_count<0 THEN 1920 Error_string$="Variable reference in immediate parameter field" 1922 GOSUB Icode_err 1924 ELSE 1926 Num_parms=POS(Inst_info$[Inst_info_ptr+1],"!")-1 1928 Repeat_str$=Inst_info$[Inst_info_ptr+1;Num_parms] 1930 Inst_info$=Inst_info$[1,Inst_info_ptr]&RPT$(Repeat_str$,Repeat_count)&Inst_info$[Inst_info_ptr+Num_parms+2] 1932 END IF 1934 RETURN 1936 ! 1938 ! This subroutine is used to select a section of the instruction 1940 ! parameter string. When the first '@' is found, the last value 1942 ! added to Object(*) is used as a select value. The select value 1944 ! is used to select a section of the instruction parameter string. 1946 ! The section to be used is delimited by '@<select_value>' and 1948 ! the next '@' or end of string. 1950 ! 1952 Icode_mlty_inst:! 1954 Rel_ptr=POS(Inst_info$[Inst_info_ptr],VAL$(Object(Object_last))) 1956 IF Rel_ptr=0 THEN 1958 Error_string$="Invalid f_ready_ram <monitor> field" 1960 GOSUB Icode_err 1962 ELSE 1964 Inst_info$=Inst_info$[Inst_info_ptr+Rel_ptr-1] 1966 Inst_info_ptr=1 1968 Rel_ptr=POS(Inst_info$,"@") 1970 IF Rel_ptr<>0 THEN Inst_info$=Inst_info$[1,Rel_ptr-1] 1972 END IF 1974 RETURN 1976 ! 1978 ! This subroutine is used to insert information about the current 1980 ! instruction into Info$(*). The current opcode number and 1982 ! opcode Source(*) address are inserted into Info$(*). This is 1984 ! used by the debugger. This subroutine is only called if 1986 ! Info_info=2 1988 ! 1990 Icode_info_isrt:! 1992 ON ERROR GOTO Icode_isrt_err 1994 OUTPUT Temp$ USING "#,W,W";Old_object_last+1,Old_source_last 1996 Info$(Info_inst_base+Inst_cnt DIV 10)[((Inst_cnt MOD 10)*4)+1;4]=Temp$ 1998 Inst_cnt=Inst_cnt+1 2000 ! 2002 IF 0 THEN 2004 Icode_isrt_err:! 2006 Error_string$="Info$ array not large enough" 2008 GOSUB Icode_fatal_err 2010 END IF 2012 ! 2014 OFF ERROR 2016 RETURN 2018 ! 2020 ! This subroutine is used to insert a c_nop before each user 2022 ! instruction. The debugger needs this. This subroutine should 2024 ! only be called if Info_info=2. 2026 ! 2028 Icode_insrt_nop:! 2030 IF Enable_list THEN 2032 List_last=List_last+1 2034 IF List_last>=List_size THEN 2036 Error_string$="Listing table overflow" 2038 GOSUB Icode_fatal_err 2040 ELSE 2042 List$(List_last)=RPT$(" ",15)&RPT$(" ",15)&"<c_nop>" 2044 END IF 2046 END IF 2048 GOSUB Icode_init_inst 2050 Add_object=61 ! insert c_nop 2052 GOSUB Icode_add_obj 2054 RETURN 2056 ! 2058 ! This instruction is used to init listing and error pointers 2060 ! to a new instruction state. 2062 ! 2064 Icode_init_inst:! 2066 INTEGER Use_left_field,Add_stars 2068 Use_left_field=1 2070 Add_stars=0 2072 List_ptr=List_last 2074 Old_object_last=Object_last 2076 Old_source_last=Source_last 2078 Old_list_last=List_last 2080 Old_forlbl_last=Forlbl_last 2082 Error_string$="" 2084 RETURN 2086 ! 2088 ! This subroutine is used to clean up the List_last pointer after 2090 ! an instruction has been assembled. List_ptr is used by the 2092 ! Icode_add_obj subroutine to insert parameter values into the 2094 ! listing. The Icode_next_line subroutine uses List_last. 2096 ! 2098 Icode_end_inst:! 2100 IF Enable_list THEN 2102 IF Use_left_field THEN 2104 IF List_ptr-1>List_last THEN List_last=List_ptr-1 2106 ELSE 2108 IF List_ptr>List_last THEN List_last=List_ptr 2110 END IF 2112 END IF 2114 RETURN 2116 ! 2118 ! Input parameter: INTEGER Add_object, INTEGER Add_stars 2120 ! 2122 ! This subroutine is used to add a opcode or parameter value to 2124 ! the object array. This routine also puts this value into the 2126 ! listing. If Add_stars is set, then '****' is put into the listing 2128 ! instead of the Add_object value. 2130 ! 2132 Icode_add_obj:! 2134 Object_last=Object_last+1 2136 IF Object_last>=Object_size THEN 2138 Error_string$="Object(*) array overflow" 2140 GOSUB Icode_fatal_err 2142 END IF 2144 Object(Object_last)=Add_object 2146 IF Enable_list THEN 2148 IF List_ptr>=List_size THEN 2150 Error_string$="Listing table overflow" 2152 GOSUB Icode_fatal_err 2154 List_last=List_size-2 2156 ELSE 2158 IF Use_left_field THEN 2160 List$(List_ptr)[1;4]=IVAL$(Object_last,16) 2162 IF Add_stars THEN 2164 List$(List_ptr)[5;5]=" ****" 2166 ELSE 2168 List$(List_ptr)[5;5]=" "&IVAL$(Add_object,16) 2170 END IF 2172 Use_left_field=0 2174 ELSE 2176 IF Add_stars THEN 2178 List$(List_ptr)[10;5]=",****" 2180 ELSE 2182 List$(List_ptr)[10;5]=","&IVAL$(Add_object,16) 2184 END IF 2186 List_ptr=List_ptr+1 2188 Use_left_field=1 2190 END IF 2192 END IF 2194 END IF 2196 RETURN 2198 ! 2200 ! This subroutine is called when an error occurs initialization. 2202 ! 2204 Icode_init_err:! 2206 OUTPUT CRT 2208 FOR I=MAX(0,Source_last-Err_disp_lines) TO MIN(Source_last,Source_size-1) 2210 OUTPUT CRT;Source$(I) 2212 NEXT I 2214 GOSUB Icode_fatal_err 2216 RETURN 2218 ! 2220 ! This subroutine is called when an error causes the assembler 2222 ! to quit assembling. 2224 ! 2226 Icode_fatal_err:! 2228 Error_count=Error_count+1 2230 Enable_list=Enable_list_arg 2232 IF Enable_list THEN 2234 ON ERROR GOTO Icode_err_skip 2236 List_last=List_last+1 2238 IF List_last<List_size-1 THEN 2240 List$(List_last)="***** FATAL ERROR: "&Error_string$&" *****" 2242 ELSE 2244 List_last=List_size-2 2246 List$(MAX(0,List_last))="***** FATAL ERROR: "&Error_string$&" *****" 2248 END IF 2250 OFF ERROR 2252 END IF 2254 Icode_err_skip:Enable_list=0 2256 OFF ERROR 2258 OUTPUT CRT;"***** FATAL ERROR: "&Error_string$;" *****" 2260 GOTO Icode_asm_exit 2262 RETURN 2264 ! 2266 ! This routine is called when routine error occurs. 2268 ! 2270 Icode_err:! 2272 Error_count=Error_count+1 2274 ! 2276 Object_last=Old_object_last ! reset Object(*) ptr 2278 Forlbl_last=Old_forlbl_last ! reset forward reference ptr 2280 ! 2282 Use_left_field=1 2284 Add_object=-1 ! overwrite opcode with -1 2286 GOSUB Icode_add_obj 2288 ! 2290 Inst_info_ptr=LEN(Inst_info$) ! don't get any more parms 2292 ! 2294 IF Enable_list THEN ! clean up listing 2296 List$(Old_list_last)[6,15]="FFFF " 2298 FOR I=Old_list_last+1 TO List_last 2300 List$(I)[1;15]=RPT$(" ",15) 2302 NEXT I 2304 List_last=List_last+1 2306 List$(List_last)=RPT$(" ",15)&"***** ERROR: "&Error_string$&" *****" 2308 END IF 2310 ! 2312 ! Print out section of source code on CRT 2314 ! 2316 OUTPUT CRT 2318 FOR I=MAX(Old_source_last-Err_disp_lines,0) TO MIN(Source_last,Source_size-1) 2320 OUTPUT CRT;Source$(I) 2322 NEXT I 2324 OUTPUT CRT;"***** ERROR: ";Error_string$;" *****" 2326 ! 2328 IF Error_count>Err_abrt_count THEN ! See if there are too many errors 2330 Error_string$="ICODE program has many problems" 2332 GOSUB Icode_fatal_err 2334 ELSE 2336 GOSUB Icode_next_inst 2338 END IF 2340 RETURN 2342 ! 2344 ! This subroutine is used to find the next line with a new 2346 ! instruction on it. 2348 ! 2350 Icode_next_inst:! 2352 REPEAT 2354 GOSUB Icode_next_line 2356 UNTIL Line$[1,1]<>"." 2358 GOSUB Icode_back_line 2360 RETURN 2362 ! 2364 ! This subroutine is used by the pre-pass to skip labels. 2366 ! Labels are looked at in the main assembly loop. 2368 ! 2370 Icode_skip_lbl:! 2372 Line_ptr=POS(Line$[1,17],":") 2374 IF Line_ptr<>0 THEN Line$=TRIM$(Line$[Line_ptr+1]) 2376 RETURN 2378 ! 2380 ! This subroutine is used to see if the current line has a label 2382 ! on it. If it does, then it is added to the label table. Then 2384 ! the forward reference table is searched. Each instance of a 2386 ! forward reference to the newly found label is then resolved. 2388 ! 2390 Icode_check_lbl:! check for label in line$ 2392 REPEAT 2394 Line_ptr=POS(Line$[1,17],":") 2396 IF Line_ptr<>0 THEN ! looks like we have a label 2398 ! 2400 Label$=Line$[1,Line_ptr-1] 2402 Line$=TRIM$(Line$[Line_ptr+1]) 2404 ! 2406 Lbl_last=Lbl_last+1 2408 IF Lbl_last<Lbl_tbl_size THEN 2410 Lbl_name$(Lbl_last)=Label$ 2412 ! 2414 ! If Info_info=2 then the label must point to the c_nop 2416 ! that was inserted before this instruction. 2418 ! 2420 IF Info_info=2 THEN 2422 Lbl_loc(Lbl_last)=Object_last 2424 Lbl_src_loc(Lbl_last)=Source_last 2426 ELSE 2428 Lbl_loc(Lbl_last)=Object_last+1 2430 END IF 2432 ELSE 2434 Error_string$="Label table overflow" 2436 GOSUB Icode_fatal_err 2438 RETURN 2440 END IF 2442 ! 2444 ! Now, resolve all unresolved references to this label 2446 ! 2448 REPEAT 2450 Forlbl_pos=FNIcode_search(Forlbl_name$(*),Forlbl_last,Label$) 2452 IF Forlbl_pos<>-1 THEN 2454 ! 2456 ! Found forward reference to this label. Resolve it. 2458 ! 2460 Int_hi=0 ! hi word must be zero 2462 Int_lo=Lbl_loc(Lbl_last) ! use same addr as put in lbl table 2464 Object(Forlbl_loc(Forlbl_pos))=Int_hi ! Addr hi 2466 Object(Forlbl_loc(Forlbl_pos)+1)=Int_lo ! Addr lo 2468 ! 2470 ! Move last element in forward reference list into this pos 2472 ! 2474 Forlbl_name$(Forlbl_pos)=Forlbl_name$(Forlbl_last) 2476 Forlbl_loc(Forlbl_pos)=Forlbl_loc(Forlbl_last) 2478 ! 2480 IF Enable_list THEN ! Must also fill in listing. 2482 IF Forlbl_list_lft(Forlbl_pos) THEN 2484 List$(Forlbl_list_pos(Forlbl_pos))[6;9]=IVAL$(Int_hi,16)&","&IVAL$(Int_lo,16) 2486 ELSE 2488 List$(Forlbl_list_pos(Forlbl_pos))[10;5]=","&IVAL$(Int_hi,16) 2490 List$(Forlbl_list_pos(Forlbl_pos)+1)[6;4]=IVAL$(Int_lo,16) 2492 END IF 2494 Forlbl_list_lft(Forlbl_pos)=Forlbl_list_lft(Forlbl_last) 2496 Forlbl_list_pos(Forlbl_pos)=Forlbl_list_pos(Forlbl_last) 2498 END IF 2500 Forlbl_last=Forlbl_last-1 ! One less forward reference now 2502 END IF 2504 UNTIL Forlbl_pos=-1 2506 END IF 2508 ! 2510 ! If label was only thing on line, then we still need to check for 2512 ! a label on the next line. 2514 IF Line$="" THEN 2516 IF Enable_list THEN List$(List_last)[1;4]=IVAL$(Object_last+1,16) 2518 GOSUB Icode_next_line 2520 Line_ptr=POS(Line$[1,17],":") 2522 END IF 2524 UNTIL Line$<>"" AND Line$<>"EL_COMPLETO" AND Line_ptr=0 2526 RETURN 2528 ! 2530 ! This subroutine is used to get Opcode$ out of the current input 2532 ! line. 2534 ! 2536 Icode_get_opcod:! 2538 Line_ptr=POS(Line$," ") 2540 IF Line_ptr=0 THEN 2542 Opcode$=Line$[1,MIN(20,LEN(Line$))] 2544 Line$="" 2546 ELSE 2548 Opcode$=Line$[1,MIN(Line_ptr-1,20)] 2550 Line$=TRIM$(Line$[Line_ptr+1]) 2552 END IF 2554 RETURN 2556 ! 2558 ! This subroutine is used when the next parameter in the current 2560 ! instruction is an ICODE address (c_goto label_name). Note that 2562 ! must be a string. i.e. not absolute jumps. 2564 ! 2566 Icode_get_label:! 2568 Enable_const=0 ! Label field may not be a CONST 2570 GOSUB Icode_get_arg 2572 IF Arg$="" THEN 2574 Error_string$="Missing label specification" 2576 GOSUB Icode_err 2578 ELSE 2580 ! 2582 ! Search label table 2584 ! 2586 Lbl_pos=FNIcode_search(Lbl_name$(*),Lbl_last,Arg$) 2588 IF Lbl_pos<>-1 THEN ! found it 2590 Add_object=0 2592 GOSUB Icode_add_obj 2594 Add_object=Lbl_loc(Lbl_pos) 2596 GOSUB Icode_add_obj 2598 ELSE 2600 Forlbl_last=Forlbl_last+1 ! insert in forward reference table 2602 Forlbl_name$(Forlbl_last)=Arg$ 2604 Forlbl_loc(Forlbl_last)=Object_last+1 2606 IF Enable_list THEN 2608 Forlbl_list_pos(Forlbl_last)=List_ptr 2610 Forlbl_list_lft(Forlbl_last)=Use_left_field 2612 END IF 2614 Add_stars=1 ! put stars in listing until this 2616 Add_object=0 ! reference is resolved. 2618 GOSUB Icode_add_obj 2620 Add_object=0 2622 GOSUB Icode_add_obj 2624 Add_stars=0 2626 END IF 2628 END IF 2630 RETURN 2632 ! 2634 ! Input: Enable_const 2636 ! Output: Arg$, REAL Arg, INTEGER Missing_arg 2638 ! 2640 ! This routine is used to get the next parameter from the Source$(*) 2642 ! array. The next parameter may be on the current line or on a 2644 ! continuation line. The next parameter may be terminated by a 2646 ! space, comma or an end-of-line. If the parameter is itself a 2648 ! numerical value, either decimal or hex ($<hex_num>), then Arg is 2650 ! set to the value and Arg$="". If the parameter isn't a numerical 2652 ! value then Arg is undefined and Arg$ is set the the parameter 2654 ! string. If Enable_const is active, then the CONST table is searched 2656 ! to see if Arg$ is defined. 2658 ! 2660 Icode_get_arg: ! returns Arg$, Arg and Missing_arg 2662 Missing_arg=0 2664 WHILE Line$="" 2666 GOSUB Get_cont_line ! returns Line$ and Missing_arg 2668 END WHILE 2670 IF Missing_arg THEN 2672 Arg$="" 2674 Arg=-1 2676 ELSE 2678 Line_ptr=POS(Line$,",") ! Is there a comma delimiter 2680 IF Line_ptr=0 THEN ! Nope 2682 Line_ptr=POS(Line$," ") 2684 IF Line_ptr=0 THEN 2686 Arg$=Line$ 2688 Line$="" 2690 ELSE 2692 Arg$=Line$[1,MIN(16,Line_ptr-1)] 2694 Line$=TRIM$(Line$[Line_ptr+1]) 2696 END IF 2698 ELSE ! Yup 2700 Int_temp=POS(Line$," ") ! Now see if there is a space between 2702 ! the end of the param and the comma. 2704 IF Int_temp<>0 THEN Line_ptr=MIN(Int_temp,Line_ptr) ! Yes 2706 Arg$=TRIM$(Line$[1,MIN(16,Line_ptr-1)]) 2708 IF Arg$="" THEN 2710 Missing_arg=1 2712 ELSE 2714 IF Line$[Line_ptr;1]="," THEN ! Remove Arg$ from Line$ 2716 Line$=TRIM$(Line$[Line_ptr+1]) 2718 ELSE 2720 Line$=TRIM$(Line$[Line_ptr+1]) 2722 IF Line$[1,1]="," THEN Line$=TRIM$(Line$[2]) 2724 END IF 2726 END IF 2728 END IF 2730 ! See if Arg$ has a 2732 CALL Icode_eval_str(Arg$,Arg,Missing_arg) ! numerical value. 2734 IF Arg$<>"" AND Enable_const THEN 2736 Const_pos=FNIcode_search(Const_name$(*),Const_last,Arg$) 2738 IF Const_pos<>-1 THEN 2740 Arg=Const_val(Const_pos) 2742 Arg$="" 2744 END IF 2746 END IF 2748 END IF 2750 RETURN 2752 ! 2754 ! Output: Line$, Missing_arg 2756 ! 2758 ! This subroutine is used to get a continuation line from the Source$(*) 2760 ! array. If the next line isn't a continuation line (first non space 2762 ! char on line must be '.'), then Missing_arg is set true. 2764 ! 2766 Get_cont_line:! 2768 INTEGER Done_cont_line 2770 Done_cont_line=0 2772 REPEAT 2774 GOSUB Icode_next_line ! returns Line$ and Skipped_lines 2776 IF Line$[1,1]<>"." OR Skipped_lines>0 THEN 2778 Missing_arg=1 2780 GOSUB Icode_back_line 2782 Done_cont_line=1 2784 ELSE 2786 Line$=TRIM$(Line$[2]) 2788 IF LEN(Line$)>=1 THEN Done_cont_line=1 2790 END IF 2792 UNTIL Done_cont_line 2794 RETURN 2796 ! 2798 ! This subroutine is used to move back one line in the Source$(*) 2800 ! array and the List$(*) array. 2802 ! 2804 Icode_back_line:! 2806 Source_last=Source_last-1 2808 IF Enable_list THEN 2810 List$(List_last)="" 2812 List_last=List_last-1 2814 END IF 2816 RETURN 2818 ! 2820 ! Output: Line$ and Skipped_lines 2822 ! 2824 ! This subroutine is used to get the next source line. It check 2826 ! to see when the end of the Source$(*) array has been found. If 2828 ! so, then Line$="EL_COMPLETO". 2830 ! 2832 Icode_next_line:! 2834 INTEGER Skipped_lines 2836 Skipped_lines=-1 2838 REPEAT 2840 Skipped_lines=Skipped_lines+1 2842 Source_last=Source_last+1 2844 IF Source_last>=Source_size THEN 2846 Line$="EL_COMPLETO" 2848 ELSE 2850 Line$=Source$(Source_last) 2852 END IF 2854 ! Insert line into List$(*) 2856 IF Enable_list THEN 2858 List_last=List_last+1 2860 IF List_last>=List_size THEN 2862 List_last=List_size-2 2864 Error_string$="Listing table overflow" 2866 GOSUB Icode_fatal_err 2868 END IF 2870 List_line_len=LEN(List$(List_last)) 2872 ON ERROR GOTO Icode_lstr_smal ! List$ elements may be too small 2874 IF List_line_len=0 THEN 2876 List$(List_last)=RPT$(" ",15)&Line$ 2878 ELSE 2880 IF List_line_len<=15 THEN List$(List_last)=List$(List_last)&RPT$(" ",15-List_line_len)&Line$ 2882 END IF 2884 OFF ERROR 2886 END IF 2888 ! 2890 ! Strip off comments. This assumes no '!' inside string parameter. 2892 ! Also, convert everything to upper case. 2894 ! 2896 Line_ptr=POS(Line$,"!") 2898 IF Line_ptr<>0 THEN 2900 Line$=UPC$(TRIM$(Line$[1,Line_ptr-1])) 2902 ELSE 2904 Line$=UPC$(TRIM$(Line$)) 2906 END IF 2908 UNTIL LEN(Line$)<>0 2910 ! If an error occurs during the assignment of 2912 IF 0 THEN ! Line$ to List$( ), then a jump is made to 2914 Icode_lstr_smal:OFF ERROR ! this section of code. 2916 Error_string$="List$(*) lines need to be longer" 2918 GOSUB Icode_fatal_err 2920 END IF 2922 RETURN 2924 ! 2926 Icode_asm_off: ! This routine is used to put semi-unassembled 2928 INTEGER Arg_count ! data into the program. The first field after 2930 INTEGER Current_arg ! ASM_OFF is the count and must be immediate, 2932 Enable_const=1 ! or CONST The next <count> fields must be 2934 GOSUB Icode_get_arg ! immediate, CONST, VAR. 2936 IF Missing_arg THEN 2938 Error_string$="Expecting ASM_OFF parameter count" 2940 GOSUB Icode_err 2942 RETURN 2944 END IF 2946 IF Arg$<>"" THEN 2948 Error_string$="ASM_OFF parameter count must be immediate" 2950 GOSUB Icode_err 2952 RETURN 2954 END IF 2956 IF Arg<1 OR Arg>100 THEN 2958 Error_string$="Invalid ASM_OFF parameter count field" 2960 GOSUB Icode_err 2962 RETURN 2964 END IF 2966 Arg_count=Arg 2968 FOR Current_arg=1 TO Arg_count 2970 Enable_const=1 2972 GOSUB Icode_get_arg 2974 IF Missing_arg THEN 2976 Error_string$="Expecting ASM_OFF parameter" 2978 GOSUB Icode_err 2980 RETURN 2982 END IF 2984 IF Arg$<>"" THEN ! and VARs may also be in the data stream. 2986 IF Arg$[1;1]="@" THEN 2988 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2]) 2990 IF Var_pos<>-1 THEN 2992 Arg=-(Var_num(Var_pos)+16384) 2994 ELSE 2996 Error_string$="Indirect variable undefined - '"&Arg$[2]&"'" 2998 GOSUB Icode_err 3000 RETURN 3002 END IF 3004 ELSE 3006 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$) 3008 IF Var_pos<>-1 THEN 3010 Arg=-Var_num(Var_pos) 3012 ELSE 3014 Error_string$="Undefined symbol - '"&Arg$&"'" 3016 GOSUB Icode_err 3018 RETURN 3020 END IF 3022 END IF 3024 END IF 3026 IF Arg>Max_16_int OR Arg<Min_16_int THEN 3028 Error_string$="Invalid ASM_OFF parameter value - '"&VAL$(Arg)&"'" 3030 GOSUB Icode_err 3032 RETURN 3034 END IF 3036 Add_object=Arg 3038 GOSUB Icode_add_obj 3040 NEXT Current_arg 3042 RETURN 3044 ! 3046 ! This subroutine is used to assemble a 32 bit integer parameter from 3048 ! from the source code. The parameter must be a CONST reference or 3050 ! an immediate in line value. 3052 ! 3054 Icode_get_int:! 3056 Enable_const=1 3058 GOSUB Icode_get_arg 3060 IF Missing_arg THEN 3062 Error_string$="Missing 32 bit integer parameter" 3064 GOSUB Icode_err 3066 RETURN 3068 END IF 3070 IF Arg$<>"" THEN 3072 Error_string$="Undefined CONST - '"&Arg$&"'" 3074 GOSUB Icode_err 3076 RETURN 3078 END IF 3080 IF Arg>Max_32_int OR Arg<Min_32_int THEN 3082 Error_string$="Invaid integer parameter - '"&VAL$(Arg)&"'" 3084 GOSUB Icode_err 3086 RETURN 3088 END IF 3090 CALL Lib_32_to_16(Arg,Int_hi,Int_lo) 3092 Add_object=Int_hi 3094 GOSUB Icode_add_obj 3096 Add_object=Int_lo 3098 GOSUB Icode_add_obj 3100 RETURN 3102 ! 3104 ! This subroutine is used to assemble a 16 bit integer parameter from 3106 ! from the source code. The parameter must be a CONST reference or 3108 ! an immediate in line value. 3110 ! 3112 Icode_get_immed:! 3114 Enable_const=1 3116 GOSUB Icode_get_arg 3118 IF Missing_arg THEN 3120 Error_string$="Missing immediate data parameter" 3122 GOSUB Icode_err 3124 RETURN 3126 END IF 3128 IF Arg$<>"" OR Arg>Max_16_int OR Arg<Min_16_int THEN 3130 IF Arg$<>"" THEN 3132 Error_string$="Invalid immediate parameter - '"&Arg$[1,MIN(20,LEN(Arg$))]&"'" 3134 ELSE 3136 Error_string$="Invalid immediate parameter - '"&VAL$(Arg)&"'" 3138 END IF 3140 GOSUB Icode_err 3142 RETURN 3144 END IF 3146 Add_object=Arg 3148 GOSUB Icode_add_obj 3150 RETURN 3152 ! 3154 ! This subroutine is used to assemble an immediate floating point 3156 ! number from the source code. Number may also be a CONST 3158 ! 3160 Icode_get_float:! 3162 INTEGER I1,I2,I3,I4 3164 Enable_const=1 3166 GOSUB Icode_get_arg 3168 IF Missing_arg THEN 3170 Error_string$="Missing floating point parameter" 3172 GOSUB Icode_err 3174 RETURN 3176 END IF 3178 IF Arg$<>"" THEN 3180 Error_string$="Undefined floating point CONST - '"&Arg$&"'" 3182 GOSUB Icode_err 3184 RETURN 3186 END IF 3188 CALL Lib_float_to_64(Arg,I1,I2,I3,I4) 3190 Add_object=I1 3192 GOSUB Icode_add_obj 3194 Add_object=I2 3196 GOSUB Icode_add_obj 3198 Add_object=I3 3200 GOSUB Icode_add_obj 3202 Add_object=I4 3204 GOSUB Icode_add_obj 3206 RETURN 3208 ! 3210 ! This routine is used to assemble a string parameter. This string 3212 ! must be between single quotes. ICODE instructions that call for 3214 ! a string parameter also call for a string length word. The 3216 ! assembler will count the length of the string and insert the string 3218 ! length field for the user. 3220 ! 3222 Icode_get_str:! 3224 INTEGER Str_len 3226 Missing_arg=0 3228 WHILE Line$="" 3230 GOSUB Get_cont_line 3232 END WHILE 3234 IF Missing_arg THEN 3236 Error_string$="Missing string parameter" 3238 GOSUB Icode_err 3240 RETURN 3242 END IF 3244 IF Line$[1;1]<>"'" THEN 3246 Error_string$="Missing first ' in string parameter" 3248 GOSUB Icode_err 3250 ELSE 3252 Line$=Line$[2] 3254 Str_len=POS(Line$,"'") 3256 IF Str_len=0 THEN 3258 Error_string$="Missing second ' in string parameter" 3260 GOSUB Icode_err 3262 ELSE 3264 Str_len=Str_len-1 3266 Arg$=Line$[1,Str_len] 3268 Line$=Line$[Str_len+2] 3270 IF Str_len MOD 2=1 THEN 3272 Arg$=Arg$&" " ! string should fall on word boundary 3274 Str_len=Str_len+1 3276 END IF 3278 Add_object=Str_len 3280 GOSUB Icode_add_obj 3282 FOR I=1 TO Str_len STEP 2 3284 Add_object=256*NUM(Arg$[I])+NUM(Arg$[I+1]) 3286 GOSUB Icode_add_obj 3288 NEXT I 3290 END IF 3292 END IF 3294 RETURN 3296 ! 3298 ! This subroutine is used to assemble a 'general' parameter. 3300 ! General means that it can be immediate, CONST or VAR. 3302 ! 3304 Icode_get_param:! 3306 Enable_const=1 3308 GOSUB Icode_get_arg 3310 IF Missing_arg THEN 3312 Error_string$="Missing parameter" 3314 GOSUB Icode_err 3316 RETURN 3318 END IF 3320 IF Arg$<>"" THEN 3322 IF Arg$[1;1]="@" THEN 3324 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2]) 3326 IF Var_pos=-1 THEN 3328 Error_string$="Undefined indirect variable - '"&Arg$[2]&"'" 3330 GOSUB Icode_err 3332 RETURN 3334 END IF 3336 Arg=-(Var_num(Var_pos)+16384) 3338 ELSE 3340 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$) 3342 IF Var_pos<>-1 THEN 3344 Arg=-Var_num(Var_pos) 3346 ELSE 3348 Error_string$="Undefined parameter symbol - '"&Arg$&"'" 3350 GOSUB Icode_err 3352 RETURN 3354 END IF 3356 END IF 3358 END IF ! IF 0 THEN 3360 IF Arg>Max_16_int OR Arg<Min_16_int THEN 3362 Error_string$="Invalid parameter value - '"&VAL$(Arg)&"'" 3364 GOSUB Icode_err 3366 RETURN 3368 END IF 3370 Add_object=Arg 3372 GOSUB Icode_add_obj 3374 RETURN 3376 ! 3378 ! This subroutine is used to assemble a block id parameter. 3380 ! The block may be DEFBLK_VAR, DEFBLK_CON, DEFBLK_SP, DEFBLK_MAIN 3382 ! or DEFBLK_EXT. 3384 ! 3386 Icode_get_block:! 3388 INTEGER Blk_id_arg,Blk_index 3390 Enable_const=0 3392 GOSUB Icode_get_arg 3394 IF Arg$="" THEN 3396 Error_string$="Illegal immediate block specification" 3398 GOSUB Icode_err 3400 ELSE 3402 IF Arg$[1;1]="^" THEN 3404 Blk_index=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$[2]) 3406 IF Blk_index=-1 THEN 3408 IF FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$[2])<>-1 OR FNIcode_search(Blkcon_name$(*),Blkcon_last,Arg$[2])<>-1 THEN 3410 Error_string$="'"&Arg$[2]&"' is not of auto allocate class" 3412 GOSUB Icode_err 3414 ELSE 3416 Error_string$="Undefined auto allocate block - '"&Arg$[2]&"'" 3418 GOSUB Icode_err 3420 END IF 3422 ELSE 3424 IF Blkext_hsize(Blk_index)=0 THEN 3426 Error_string$="No header allocated for '"&Arg$[2]&"'" 3428 GOSUB Icode_err 3430 ELSE 3432 Blk_id_arg=-(Blkext_id(Blk_index)+1) 3434 END IF 3436 END IF 3438 ELSE 3440 Blk_index=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$) 3442 IF Blk_index<>-1 THEN 3444 Blk_id_arg=-Blkext_id(Blk_index) 3446 ELSE 3448 Blk_index=FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$) 3450 IF Blk_index<>-1 THEN 3452 Blk_id_arg=-Blkvar_id(Blk_index) 3454 ELSE 3456 Blk_index=FNIcode_search(Blkcon_name$(*),Blkcon_last,Arg$) 3458 IF Blk_index<>-1 THEN 3460 Blk_id_arg=Blkcon_id(Blk_index) 3462 ELSE 3464 Error_string$="Undefined block - '"&Arg$&"'" 3466 GOSUB Icode_err 3468 RETURN 3470 END IF 3472 END IF 3474 END IF 3476 END IF 3478 END IF 3480 Add_object=Blk_id_arg 3482 GOSUB Icode_add_obj 3484 RETURN 3486 ! 3488 ! This subroutine is used to assemble a variable reference parameter. 3490 ! A DEFBLK_VAR parameter may also be used in this field. 3492 ! 3494 Icode_get_var:! 3496 Enable_const=0 3498 GOSUB Icode_get_arg 3500 IF Arg$<>"" THEN 3502 IF Arg$[1;1]="@" THEN ! Is this an indirect variable 3504 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$[2]) 3506 IF Var_pos=-1 THEN 3508 Error_string$="Undefined indirect variable - '"&Arg$[2]&"'" 3510 GOSUB Icode_err 3512 ELSE 3514 Arg=-(Var_num(Var_pos)+16384) 3516 END IF 3518 ELSE 3520 Var_pos=FNIcode_search(Var_name$(*),Var_last,Arg$) 3522 IF Var_pos<>-1 THEN 3524 Arg=-Var_num(Var_pos) 3526 ELSE 3528 IF Arg$[1;1]="^" THEN ! Header block 3530 Blkext_pos=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$[2]) 3532 IF Blkext_pos<>-1 THEN 3534 IF Blkext_hsize(Blkext_pos)>0 THEN 3536 Arg=Blkext_id(Blkext_pos)+1 3538 ELSE 3540 Error_string$="No header block allocated for '"&Arg$[2]&"'" 3542 GOSUB Icode_err 3544 END IF 3546 ELSE 3548 Error_string$="'"&Arg$[2]&"' not of auto allocate class" 3550 GOSUB Icode_err 3552 END IF 3554 ELSE 3556 Blkext_pos=FNIcode_search(Blkext_name$(*),Blkext_last,Arg$) 3558 IF Blkext_pos<>-1 THEN 3560 Arg=-Blkext_id(Blkext_pos) 3562 ELSE 3564 Blkvar_pos=FNIcode_search(Blkvar_name$(*),Blkvar_last,Arg$) 3566 IF Blkvar_pos<>-1 THEN 3568 Arg=-Blkvar_id(Blkvar_pos) 3570 ELSE 3572 Error_string$="Undefined variable - '"&Arg$&"'" 3574 GOSUB Icode_err 3576 END IF 3578 END IF 3580 END IF 3582 END IF 3584 END IF 3585 ELSE 3586 Error_string$="Immediate parameter in variable reference field" 3587 GOSUB Icode_err 3589 END IF 3590 Add_object=Arg 3591 GOSUB Icode_add_obj 3592 RETURN 3594 ! 3596 ! This subroutine is used to allocate all the internal tables 3598 ! needed by the assembler. 3600 ! 3602 Icode_alloc_tbl:! 3604 Lbl_last=-1 3606 ALLOCATE Lbl_name$(0:MAX(Lbl_tbl_size-1,0))[16],INTEGER Lbl_loc(0:MAX(Lbl_tbl_size-1,0)) 3608 IF Info_info=2 THEN ALLOCATE INTEGER Lbl_src_loc(0:MAX(Lbl_tbl_size-1,0)) 3610 Var_last=-1 3612 ALLOCATE Var_name$(0:MAX(Var_tbl_size-1,0))[16],INTEGER Var_num(0:MAX(Var_tbl_size-1,0)) 3614 Forlbl_last=-1 3616 ALLOCATE Forlbl_name$(0:MAX(Forlbl_tbl_size-1,0))[16],INTEGER Forlbl_loc(0:MAX(Forlbl_tbl_size-1,0)) 3618 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)) 3620 Blkvar_last=-1 3622 ALLOCATE Blkvar_name$(0:MAX(Blkvar_tbl_size-1,0))[16],INTEGER Blkvar_id(0:MAX(Blkvar_tbl_size-1,0)) 3624 Blkext_last=-1 3626 ALLOCATE Blkext_name$(0:MAX(Blkext_tbl_size-1,0))[16],INTEGER Blkext_id(0:MAX(Blkext_tbl_size-1,0)) 3628 ALLOCATE INTEGER Blkext_type(0:MAX(Blkext_tbl_size-1,0)) 3630 ALLOCATE Blkext_hsize(0:MAX(Blkext_tbl_size-1,0)),Blkext_size(0:MAX(Blkext_tbl_size-1,0)) 3632 Blkcon_last=-1 3634 ALLOCATE Blkcon_name$(0:MAX(Blkcon_tbl_size-1,0))[16],INTEGER Blkcon_id(0:MAX(Blkcon_tbl_size-1,0)) 3636 Const_last=-1 3638 ALLOCATE Const_name$(0:MAX(Const_tbl_size-1,0))[16],Const_val(0:MAX(Const_tbl_size-1,0)) 3640 RETURN 3642 ! 3644 ! This subroutine is used to do some checks on Info$(*) to make sure 3646 ! that it is of the correct size. 3648 ! 3650 Icode_chk_info:! 3652 Info_hdr_size=6 3654 IF Info_info>0 THEN 3656 IF Info_size<Info_hdr_size THEN 3658 Error_string$="Info$ array < "&VAL$(Info_hdr_size)&" elements" 3660 GOSUB Icode_init_err 3662 END IF 3664 IF BASE(Info$,1)<>0 THEN 3666 Error_string$="Info$(*) index must start at zero" 3668 GOSUB Icode_init_err 3670 END IF 3672 ON ERROR GOTO Icode_info_smal ! Each line must be 40 chars long 3674 FOR I=1 TO Info_hdr_size 3676 Info$(I)=RPT$(" ",40) 3678 NEXT I 3680 OFF ERROR 3682 IF 0 THEN 3684 Icode_info_smal:OFF ERROR 3686 Error_string$="Info$(*) string elements < 40 chars" 3688 GOSUB Icode_init_err 3690 END IF 3692 END IF 3694 RETURN 3696 ! 3698 Icode_fill_info:! 3700! 3702! This subroutine is used to fill the Info$(*) array after all 3704! source code has been assembled will lots of little things 3706! that the debugger, downloader, etc... need to know. 3708! 3710! Info$(*) format: 3712! 3714! char->0 1 2 3 4 3716! line 1234567890123456789012345678901234567890 3718! 0 < a >< b >< c >< d >< e > 3720! 1 < i >< j >< k >< l > 3722! 2 < q >< r >< s >< t > 3724! 3 < x >< y >< z > 3726! 4 < F >< G >< H > 3728! 5 < I >< J > 3730! . 3732! k < Inst_info table > 3734! . 3736! . 3738! i < Blkext table > 3740! . 3742! . 3744! q < blkvar table > 3746! . 3748! . 3750! x < Blkcon table > 3752! . 3754! . 3756! F < Var table > 3758! . 3760! . 3762! I < Lbl table > 3764! . 3766! . 3768! z < Debugger history queue space > 3770! . 3772! a: Info_info 3774! b: ICODE program id 3776! c: Info$(*) header size (6) 3778! d: Info_size 3780! e: # of vars reserved. For VAR, DEFBLK_VAR, etc... 3782! 3784! i: Start of Blkext table in Info$(*) 3786! j: # of Blkext table lines in Info$(*) 3788! k: Object_size 3790! l: Source_size 3792! 3794! q: Start of Blkvar table in Info$(*) 3796! r: # of Blkvar table lines in Info$(*) 3798! s: Start of Instruction table in Info$(*) 3800! t: # of Instructions in Info$(*). NOT # of instruction lines. 3802! 3804! x: Start of Blkcon table in Info$(*) 3806! y: # of Blkcon table lines in Info$(*) 3808! z: Start of 3 lines in Info$(*) reserved for debugger history queue 3810! 3812! F: Start of var table in Info$(*) 3814! G: # of var table lines in Info$(*) 3816! H: Object(*) address of last set break point. Used by debugger. 3818! 3820! I: Start of label table in Info$(*) 3822! J: # of label table lines in Info$(*) 3824! 3826! Inst_info table: Each line may have information about a maximum of 10 3828! assembled instructions. Information about a single 3830! instruction consists of 4 bytes. These bytes are in 3832! binary format with the first 2 bytes indicating the 3834! object address and the second 2 bytes indicating the 3836! source address. 3838! 3840! Blkext table: Each line has information about one DEFBLK_SP,DEFBLK_MAIN 3842! or DEFBLK_EXT user defined block. Chars 1 through 16 are 3844! the block name, char 17 is a mode byte, chars 18 through 3846! 22 hold the variable number, chars 23 through 28 hold 3848! the block size, chars 29 through 34 hold the header block 3850! size, and chars 35 through 39 hold the block id. The 3852! mode byte indicates the block type and whether or not 3854! the downloader should allocate this block at download 3856! time. Mode codes are as follows: 3858! 0 - undefined yet 3860! 1 - MAIN auto allocate block 3862! 2 - SP auto allocate block 3864! 3 - MAIN user allocate block 3866! 4 - SP user allocate block 3868! 3870! Blkvar table: Each line has information about one DEFBLK_VAR block. 3872! Characters 1 through 16 hold the block name and chars 3874! 17 through 21 hold the variable number that contains the 3876! block id. 3878! 3880! Blkcon table: Each line has information about one DEFBLK_CON block. 3882! Characters 1 through 16 hold the block name and chars 3884! 17 through 21 hold the block id. 3886! 3888! Var table: Each line has information about one VARiable. Characters 3890! 1 through 16 hold the variable name and chars 17 through 3892! 21 hold the variable number. 3894! 3896! Lbl table: Each line has information about one label. Characters 3898! 1 through 16 hold the label name and chars 17 through 21 3900! hold the label source address. 3902! 3904! Debugger history queue space: These 3 lines are used as storage space 3906! by the debugger. The first line contains 3908! 2 fields. Chars 1 through 5 hold the 3910! Hist_fifo_ptr and chars 6 through 10 hold 3912! Hist_fifo_wrap. The second line contains 3914! the ICODE history object address list. 3916! This list can hold up to 20 two byte 3918! binary entries. The third line contains 3920! the ICODE history opcode list. This list 3922! can also hold up to 20 two byte binary 3924! entries. This list is used to hold the 3926! ICODE history queue. See IHQ? HP-IB 3928! command. 3930! 3932! 3934 IF Info_info<>0 THEN 3936 ! 3938 ! Find out how many lines need to be in Info$(*) 3940 ! 3942 IF Info_info=1 THEN Lines_needed=Blkext_last+1+Info_hdr_size 3944 ! 3946 IF Info_info=2 THEN 3948 Info_inst_cnt=Inst_cnt DIV 10 3950 IF Inst_cnt MOD 10<>0 THEN Info_inst_cnt=Info_inst_cnt+1 3952 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 3954 Lines_needed=Lines_needed+3 ! Debugger needs this space 3956 END IF ! to keep the history list 3958 ! 3960 IF Lines_needed>Info_size THEN 3962 Error_string$="Info$ array not large enough" 3964 GOSUB Icode_fatal_err 3966 END IF 3968 ! 3970 REDIM Info$(0:Lines_needed-1) 3972 ! 3974 ! Get indexes into Info$(*) where each table will go 3976 ! 3978 Blkext_infostrt=Info_hdr_size+Info_inst_cnt 3980 Blkvar_infostrt=Blkext_infostrt+Blkext_last+1 3982 Blkcon_infostrt=Blkvar_infostrt+Blkvar_last+1 3984 Var_infostrt=Blkcon_infostrt+Blkcon_last+1 3986 Lbl_infostrt=Var_infostrt+Var_last+1 3988 ! 3990 ! Start filling in Info$(*) with info. 3992 ! 3994 IF Info_info=2 THEN 3996 Dbg_infostrt=Lbl_infostrt+Lbl_last+1 !Reserve 3 lines for hist 3998 ! table used by debugger. 4000 Info$(Dbg_infostrt)[1,5]=VAL$(-1) ! Init Hist_fifo_ptr 4002 Info$(Dbg_infostrt)[6,10]=VAL$(0) ! Init Hist_fifo_wrap 4004 Info$(Dbg_infostrt+1)=RPT$(" ",40) 4006 Info$(Dbg_infostrt+2)=RPT$(" ",40) 4008 END IF 4010 ! 4012 Info$(0)[1,5]=VAL$(Info_info) 4014 Info$(0)[6,10]=VAL$(-1) 4016 Info$(0)[11,15]=VAL$(Info_hdr_size) 4018 Info$(0)[16,20]=VAL$(Lines_needed) 4020 Info$(0)[21,25]=VAL$(Vars_allocated) 4022 ! 4024 IF Blkext_last=-1 THEN 4026 Info$(1)[1,5]=VAL$(0) 4028 ELSE 4030 Info$(1)[1,5]=VAL$(Blkext_infostrt) 4032 END IF 4034 Info$(1)[6,10]=VAL$(Blkext_last+1) 4036 Info$(1)[11,15]=VAL$(Object_last+1) 4038 Info$(1)[16,20]=VAL$(Source_last) 4040 ! 4042 IF Info_info=1 THEN 4044 FOR I=2 TO 5 4046 Info$(I)[1,5]=VAL$(0) 4048 Info$(I)[6,10]=VAL$(0) 4050 NEXT I 4052 ELSE 4054 Info$(2)[1,5]=VAL$(Blkvar_infostrt) 4056 Info$(2)[6,10]=VAL$(Blkvar_last+1) 4058 Info$(2)[11,15]=VAL$(Info_inst_base) 4060 Info$(2)[16,20]=VAL$(Inst_cnt) 4062 Info$(3)[1,5]=VAL$(Blkcon_infostrt) 4064 Info$(3)[6,10]=VAL$(Blkcon_last+1) 4066 Info$(3)[11,15]=VAL$(Dbg_infostrt) ! used by debugger 4068 Info$(4)[1,5]=VAL$(Var_infostrt) 4070 Info$(4)[6,10]=VAL$(Var_last+1) 4072 Info$(4)[11,15]=VAL$(-1) ! used by debugger to 4074 Info$(5)[1,5]=VAL$(Lbl_infostrt) 4076 Info$(5)[6,10]=VAL$(Lbl_last+1) 4078 Info$(5)[11;1]=VAL$(0) ! Disp_vars_hex = 0 4080 Info$(5)[12;1]=VAL$(0) ! disp_blks_hex = 0 4082 END IF 4084 ! 4086 ! Fill in externally allocated block table 4088 ! 4090 Blkext_ptr=-1 4092 FOR I=Blkext_infostrt TO Blkext_infostrt+Blkext_last 4094 Blkext_ptr=Blkext_ptr+1 4096 Info$(I)[1,16]=Blkext_name$(Blkext_ptr) 4098 Info$(I)[17;1]=VAL$(Blkext_type(Blkext_ptr)) 4100 Info$(I)[18,22]=VAL$(Blkext_id(Blkext_ptr)) 4102 Info$(I)[23,28]=VAL$(Blkext_size(Blkext_ptr)) 4104 Info$(I)[29,34]=VAL$(Blkext_hsize(Blkext_ptr)) 4106 NEXT I 4108 ! 4110 IF Info_info=2 THEN 4112 ! 4114 ! Fill in DEFBLK_VAR table 4116 ! 4118 Blkvar_ptr=-1 4120 FOR I=Blkvar_infostrt TO Blkvar_infostrt+Blkvar_last 4122 Blkvar_ptr=Blkvar_ptr+1 4124 Info$(I)[1,16]=Blkvar_name$(Blkvar_ptr) 4126 Info$(I)[17,21]=VAL$(Blkvar_id(Blkvar_ptr)) 4128 NEXT I 4130 ! 4132 ! Fill in DEFBLK_CON table 4134 ! 4136 Blkcon_ptr=-1 4138 FOR I=Blkcon_infostrt TO Blkcon_infostrt+Blkcon_last 4140 Blkcon_ptr=Blkcon_ptr+1 4142 Info$(I)[1,16]=Blkcon_name$(Blkcon_ptr) 4144 Info$(I)[17,21]=VAL$(Blkcon_id(Blkcon_ptr)) 4146 NEXT I 4148 ! 4150 ! Fill in variable table 4152 ! 4154 Var_ptr=-1 4156 FOR I=Var_infostrt TO Var_infostrt+Var_last 4158 Var_ptr=Var_ptr+1 4160 Info$(I)[1,16]=Var_name$(Var_ptr) 4162 Info$(I)[17,21]=VAL$(Var_num(Var_ptr)) 4164 NEXT I 4166 ! 4168 ! Fill in label table 4170 ! 4172 Lbl_ptr=-1 4174 FOR I=Lbl_infostrt TO Lbl_infostrt+Lbl_last 4176 Lbl_ptr=Lbl_ptr+1 4178 Info$(I)[1,16]=Lbl_name$(Lbl_ptr) 4180 Info$(I)[17,21]=VAL$(Lbl_loc(Lbl_ptr)) 4182 Info$(I)[22,26]=VAL$(Lbl_src_loc(Lbl_ptr)) 4184 NEXT I 4186 END IF ! If info_info=2 then 4188 END IF ! If Info_info<>0 then 4190 RETURN 4192 ! 4194 Icode_forlbl_ck: ! See if there are any unresolved forward references 4196 IF Forlbl_last>-1 THEN 4198 FOR I=0 TO Forlbl_last 4200 Error_string$="ERROR: Undefined label - '"&Forlbl_name$(I)&"'" 4202 OUTPUT CRT;Error_string$ 4204 Error_count=Error_count+1 4206 IF Enable_list THEN 4208 List_last=List_last+1 4210 List$(MAX(0,MIN(List_last,List_size-1)))=RPT$(" ",15)&"***** "&Error_string$&" *****" 4212 END IF 4214 NEXT I 4216 END IF 4218 RETURN 4220 ! 4222 Icode_asm_exit: ! This routine is used to exit the assembler 4224 Disp_line$="ICODE assembly complete. " 4226 IF Error_count=0 THEN 4228 Disp_line$=Disp_line$&"No errors. "&VAL$(Source_last)&" source lines. "&VAL$(Object_last+1)&" object words." 4230 ELSE 4232 BEEP 4234 IF Error_count=1 THEN 4236 Disp_line$=Disp_line$&VAL$(Error_count)&" error." 4238 ELSE 4240 Disp_line$=Disp_line$&VAL$(Error_count)&" errors." 4242 IF Error_count>20 THEN Disp_line$=Disp_line$&" ICODE program needs work" 4244 END IF 4246 END IF 4248 DISP Disp_line$ 4250 IF Enable_list THEN 4252 List_last=List_last+1 4254 List$(MIN(List_last,List_size-1))=Disp_line$ 4256 END IF 4258 REDIM List$(0:MAX(0,MIN(List_last,List_size-1))) 4260 IF Error_count=0 THEN 4262 REDIM Source$(0:MAX(Source_last-1,0)) 4264 REDIM Object(0:MAX(Object_last,0)) 4266 END IF 4268 ! 4270 IF Error_count<>0 THEN 4272 ON ERROR GOTO Icode_who_cares 4274 REDIM Info$(0:0) 4276 Info$(0)="9" 4278 Icode_who_cares:IF 0 THEN A=1 4280 OFF ERROR 4282 END IF 4284 ! 4286 RETURN Error_count 4288 END IF ! GOSUBS IF 0 THEN 4290 ! 4292 FNEND ! Icode_assemble 4294 ! 4296 Icode_search:DEF FNIcode_search(Search_array$(*),Array_last,Search_key$) 4298! 4300! This function is used by the assembler to search a table and return 4302! an index into that table indicating where the search key was found. 4304! <Search_array$> is the array to be searched. <Array_last> is the last 4306! element in <Search_array$> that should be checked. <Search_key$> is 4308! what should be found in <Search_array$>. If <Search_key$> is found 4310! in <Search_array$> then the index into <Search_array$> is returned 4312! in the function result, else -1 is returned. 4314! 4316 INTEGER I,Int_array_last 4318 Int_array_last=Array_last 4320 IF Int_array_last>=0 THEN 4322 FOR I=0 TO Int_array_last 4324 IF Search_key$=Search_array$(I) THEN RETURN I 4326 NEXT I 4328 END IF 4330 RETURN -1 4332 FNEND 4334 ! 4336 Icode_inst_str:SUB Icode_inst_str(Opcode$,Inst_info$) 4338! 4340! This function is used by the assembler to translate an opcode mnemonic 4342! (did you know that mnemonically is a word?) into an instruction 4344! information string. The instruction information string contains 4346! the opcode number and a list of code which tell the assembler what 4348! parameters must follow. If the opcode mnemonic (who was the first 4350! person to spell mnemonic?) is undefined, then "-1" is returned. 4352! See the main assembly loop in the assembler for details on what the 4354! parameter codes mean. 4356! 4358 SELECT Opcode$[1;2] 4360 CASE "C_" 4362 SELECT Opcode$[3] 4364 CASE "BEQ" 4366 Inst_info$="57 LPP" 4368 CASE "BGE" 4370 Inst_info$="59 LPP" 4372 CASE "BGT" 4374 Inst_info$="60 LPP" 4376 CASE "BITSET" 4378 Inst_info$="54 LPP" 4380 CASE "BLE" 4382 Inst_info$="56 LPP" 4384 CASE "BLT" 4386 Inst_info$="55 LPP" 4388 CASE "BNE" 4390 Inst_info$="58 LPP" 4392 CASE "END" 4394 Inst_info$="48" 4396 CASE "GOSUB" 4398 Inst_info$="50 L" 4400 CASE "GOTO" 4402 Inst_info$="49 L" 4404 CASE "NOP" 4406 Inst_info$="61" 4408 CASE "RTS" 4410 Inst_info$="51" 4412 CASE "SP_BEQ" 4414 Inst_info$="52 LP" 4416 CASE "SP_BNE" 4418 Inst_info$="53 LP" 4420 CASE ELSE 4422 Inst_info$="-1" 4424 END SELECT 4426 CASE "F_" 4428 SELECT Opcode$[3] 4430 CASE "ASSERT_TRIG" 4432 Inst_info$="22" 4434 CASE "BLK_MC68000" 4436 Inst_info$="32 BPMRBP!" 4438 CASE "COPY_BLOCK" 4440 Inst_info$="14 BB" 4442 CASE "EXEC" 4444 Inst_info$="134 P" 4446 CASE "FAST_AVG_ADD" 4448 Inst_info$="126 BPBPPP" 4450 CASE "FAST_AVG_DIV" 4452 Inst_info$="127 BPBPPP" 4454 CASE "FAST_AVG_INIT" 4456 Inst_info$="124 BPPPPP" 4458 CASE "FLOAT_ADD" 4460 Inst_info$="86 BPBPBPP" 4462 CASE "FLOAT_AVG" 4464 Inst_info$="132 BPBPPP" 4466 CASE "FLOAT_CCONST" 4468 Inst_info$="107 BPPFF" 4470 CASE "FLOAT_CDIV" 4472 Inst_info$="101 BPBPBPP" 4474 CASE "FLOAT_CMULT" 4476 Inst_info$="98 BPBPBPP" 4478 CASE "FLOAT_CONJ" 4480 Inst_info$="116 BPBPP" 4482 CASE "FLOAT_CONST" 4484 Inst_info$="104 BPPF" 4486 CASE "FLOAT_EXTREMAL" 4488 Inst_info$="120 BPBPP" 4490 CASE "FLOAT_DINTRLVE" 4492 Inst_info$="45 BPBPBPP" 4494 CASE "FLOAT_DIV" 4496 Inst_info$="95 BPBPBPP" 4498 CASE "FLOAT_INTRLVE" 4500 Inst_info$="83 BPBPBPP" 4502 CASE "FLOAT_LOG10" 4504 Inst_info$="125 BPBPP" 4506 CASE "FLOAT_MULT" 4508 Inst_info$="92 BPBPBPP" 4510 CASE "FLOAT_PHASE" 4512 Inst_info$="119 BPBPP" 4514 CASE "FLOAT_SQRT" 4516 Inst_info$="122 BPBPP" 4518 CASE "FLOAT_SUB" 4520 Inst_info$="89 BPBPBPP" 4522 CASE "FLOAT_TO_INT" 4524 Inst_info$="113 BPBPP" 4526 CASE "FLOAT_TO_SHORT" 4528 Inst_info$="112 BPBPP" 4530 CASE "FLOAT_WINGEN" 4532 Inst_info$="138 BPPMRF!" 4534 CASE "FLOAT_XYPOW" 4536 Inst_info$="128 BPBPBPP" 4538 CASE "GET_ASCII" 4540 Inst_info$="27 PMRV!" 4542 CASE "GET_GBL_STA","GET_GLB_STA" 4544 Inst_info$="30 V" 4546 CASE "GET_HDW_STATUS" 4548 Inst_info$="29 PV" 4550 CASE "GET_SIG" 4552 Inst_info$="46 V" 4554 CASE "GET_SRQ_MASK" 4556 Inst_info$="63 V" 4558 CASE "GET_STA" 4560 Inst_info$="15 V" 4562 CASE "GET_STATUS" 4564 Inst_info$="28 PV" 4566 CASE "GET_STC" 4568 Inst_info$="16 V" 4570 CASE "GLB_COMMAND" 4572 Inst_info$="24 PS" 4574 CASE "GLB_CONTROL" 4576 Inst_info$="26 V" 4578 CASE "HPIB_COMMAND" 4580 Inst_info$="17 S" 4582 CASE "INPUT_DATA" 4584 Inst_info$="1 PBPP" 4586 CASE "INT_TO_FLOAT" 4588 Inst_info$="111 BPBPP" 4590 CASE "INT_TO_SHORT" 4592 Inst_info$="110 BPBPP" 4594 CASE "KEEP_READY_RAM" 4596 Inst_info$="66" 4598 CASE "LOAD_PROG" 4600 Inst_info$="42 BP" 4602 CASE "LOAD_SP_ALGS" 4604 Inst_info$="47 P" 4606 CASE "MC68000" 4608 Inst_info$="31 IMRBP!" 4610 CASE "MOD_COMMAND" 4612 Inst_info$="23 PS" 4614 CASE "MOD_CONTROL" 4616 Inst_info$="25 PV" 4618 CASE "MOVE_BLOCK" 4620 Inst_info$="13 BPBPP" 4622 CASE "OFF_INT" 4624 Inst_info$="38" 4626 CASE "ON_IRQ" 4628 Inst_info$="35 L" 4630 CASE "ON_SHUTDOWN" 4632 Inst_info$="37 L" 4634 CASE "ON_SP" 4636 Inst_info$="36 L" 4638 CASE "ON_SRQ" 4640 Inst_info$="34 L" 4642 CASE "OUTPUT_DATA" 4644 Inst_info$="2 PBPP" 4646 CASE "PAUSE" 4648 Inst_info$="133" 4650 CASE "POLL_MODULE" 4652 Inst_info$="39 PV" 4654 CASE "READ_DISC" 4656 Inst_info$="5 BPPPPPPPV" 4658 CASE "READ_ROM" 4660 Inst_info$="136 PV" 4662 CASE "READ_SP_STAT" 4664 Inst_info$="118 V" 4666 CASE "READY_DISC" 4668 Inst_info$="7 PPPPPBPBPV" 4670 CASE "READY_RAM" 4672 Inst_info$="8 M@0BPPPMRP!@1BPBPV" 4674 CASE "RECEIVE_DATA" 4676 Inst_info$="3 BPP" 4678 CASE "RELEASE_BUS" 4680 Inst_info$="41 P" 4682 CASE "REQUEST_BUS" 4684 Inst_info$="40" 4686 CASE "SAMPLE" 4688 Inst_info$="137 BPBPPPP" 4690 CASE "SEND_DATA" 4692 Inst_info$="4 BPP" 4694 CASE "SET_EXP_DEF" 4696 Inst_info$="129 PPPP" 4698 CASE "SET_SRQ_MASK" 4700 Inst_info$="64 P" 4702 CASE "SET_WORK_ID" 4704 Inst_info$="139 B" 4706 CASE "SHORT_ADD" 4708 Inst_info$="84 BPBPBPP" 4710 CASE "SHORT_CCONST" 4712 Inst_info$="105 BPPPPP" 4714 CASE "SHORT_CDIV" 4716 Inst_info$="99 BPBPBPP" 4718 CASE "SHORT_CMULT" 4720 Inst_info$="96 BPBPBPP" 4722 CASE "SHORT_CONJ" 4724 Inst_info$="114 BPBPP" 4726 CASE "SHORT_CONST" 4728 Inst_info$="102 BPPPP" 4730 CASE "SHORT_DINTRLVE" 4732 Inst_info$="43 BPBPBPP" 4734 CASE "SHORT_DIV" 4736 Inst_info$="93 BPBPBPP" 4738 CASE "SHORT_INTRLVE" 4740 Inst_info$="81 BPBPBPP" 4742 CASE "SHORT_MULT" 4744 Inst_info$="90 BPBPBPP" 4746 CASE "SHORT_NORM" 4748 Inst_info$="135 BPP" 4750 CASE "SHORT_SUB" 4752 Inst_info$="87 BPBPBPP" 4754 CASE "SHORT_TO_FLOAT" 4756 Inst_info$="109 BPBPP" 4758 CASE "SHORT_TO_INT" 4760 Inst_info$="108 BPBPP" 4762 CASE "SIG_PROC" 4764 Inst_info$="0 PMRM!MRBP!" 4766 CASE "SIGNAL" 4768 Inst_info$="18 P" 4770 CASE "STORE_PROG" 4772 Inst_info$="62 BPPP" 4774 CASE "SYNC" 4776 Inst_info$="33" 4778 CASE "SYNC_TIME" 4780 Inst_info$="130 P" 4782 CASE "THRUPUT" 4784 Inst_info$="9 PP" 4786 CASE "TRIG_SEQ" 4788 Inst_info$="10" 4790 CASE "TRIG_SEQ_TIME" 4792 Inst_info$="121 P" 4794 CASE "UNASSERT_TRIG" 4796 Inst_info$="21" 4798 CASE "UNDEFINED" 4800 Inst_info$="44" 4802 CASE "WAIT_FOR_SIG" 4804 Inst_info$="19 V" 4806 CASE "WAIT_TO_SIG" 4808 Inst_info$="65 P" 4810 CASE "WAIT_SRQ" 4812 Inst_info$="20" 4814 CASE "WRITE_DISC" 4816 Inst_info$="6 BPPPPPPPV" 4818 CASE "WRITE_ROM" 4820 Inst_info$="123 PP" 4822 CASE "WRITE_SP_CNTL" 4824 Inst_info$="117 P" 4826 CASE "XFER_TO_HOST" 4828 Inst_info$="11 PP" 4830 CASE "XFER_TO_MOD" 4832 Inst_info$="12 PP" 4834 CASE ELSE 4836 Inst_info$="-1" 4838 END SELECT 4840 CASE "V_" 4842 SELECT Opcode$[3] 4844 CASE "ADD" 4846 Inst_info$="71 PPV" 4848 CASE "AND" 4850 Inst_info$="68 PPV" 4852 CASE "CEQUATE" 4854 Inst_info$="75 IV" 4856 CASE "DIV" 4858 Inst_info$="74 PPV" 4860 CASE "GET16_INDEXED" 4862 Inst_info$="77 BPV" 4864 CASE "GET32_INDEXED" 4866 Inst_info$="78 BPV" 4868 CASE "MODULO" 4870 Inst_info$="70 PPV" 4872 CASE "MULT" 4874 Inst_info$="73 PPV" 4876 CASE "NOT" 4878 Inst_info$="67 PV" 4880 CASE "OR" 4882 Inst_info$="69 PPV" 4884 CASE "PUT16_INDEXED" 4886 Inst_info$="79 BPV" 4888 CASE "PUT32_INDEXED" 4890 Inst_info$="80 BPV" 4892 CASE "SUB" 4894 Inst_info$="72 PPV" 4896 CASE "VEQUATE" 4898 Inst_info$="76 VV" 4900 CASE ELSE 4902 Inst_info$="-1" 4904 END SELECT 4906 CASE ELSE 4908 Inst_info$="-1" 4910 END SELECT 4912 SUBEND 4914 ! 4916 Icode_eval_str:SUB Icode_eval_str(Str$,Str_val,Str_error) 4918! 4920! This subprogram is used to evaluate a string into a numerical quantity. 4922! <Str$> is the input string and its numerical value (if there is one) is 4924! returned in <Str_val>. This will work on decimal and hex numbers. Hex 4926! numbers must be preceeded by a '$'. If <Str$> can not be converted 4928! into a number then <Str_error> is set to 1. <Str_error> is also set 4930! to 1 if <Str$>="". 4932! 4934 Str_error=0 4936 ON ERROR GOTO Icode_no_value 4938 IF Str$="" THEN 4940 Str_error=1 4942 ELSE 4944 IF Str$[1;1]="$" THEN 4946 Str_val=DVAL(Str$[2],16) 4948 Str$="" 4950 ELSE 4952 Str_val=VAL(Str$) 4954 Str$="" 4956 END IF 4958 END IF 4960 IF 0 THEN 4962 Icode_no_value:Str_val=-1 4964 END IF 4966 OFF ERROR 4968 SUBEND 4970 ! 4972 Icode_dld:DEF FNIcode_dld(INTEGER Object(*),INTEGER Enable_info,Info$(*)) 4974! 4976! This function is used to allocate an ICODE program block, allocate 4978! some types of data blocks, and download the ICODE program into its 4980! program block. <Object(*)> is the assembled ICODE program. 4982! <Enable_info> is a flag which enables the downloader to search <Info$> 4984! for unallocated blocks. If <Enable_info> is non-zero, then <Info$> is 4986! searched for all DEFBLK_SP and DEFBLK_MAIN block types. These blocks 4988! are then allocated. Also, DEFBLK_EXT block types that have been 4990! flagged by 'FNIcode_def_ext' to be allocated by the downloader are 4992! allocated. To find out the block id of any block, 'FNIcode_ext_id' 4994! may be used after the ICODE program has been downloaded. If 4996! <Enable_info> is zero, then no blocks are allocated (except the ICODE 4998! program block). Returned in the function result is the block id of 5000! the ICODE program. If an error occurs, then an error message is 5002! displayed and a -1 is returned as the function result. 5004! 5006 DIM Line$[40],Error_string$[100],Temp$[20] 5008 Object_size=SIZE(Object,1) 5010 IF NOT FNIcode_info_ok(Info$(*),Error_string$) THEN GOTO Icode_dld_err 5012 ! 5014 IF Enable_info THEN 5016 ON ERROR GOTO Icode_info_bad 5018 Blkext_strt=VAL(Info$(1)[1,5]) 5020 Blkext_cnt=VAL(Info$(1)[6,10]) 5022 FOR I=Blkext_strt TO Blkext_strt+Blkext_cnt-1 5024 Line$=Info$(I) 5026 Block_type=VAL(Line$[17;1]) 5028 IF Block_type=0 THEN 5030 Error_string$="Block '"&TRIM$(Line$[1,16])&"' not allocated" 5032 GOTO Icode_dld_err 5034 RETURN -1 5036 ELSE 5038 Var_number=VAL(Line$[18,22]) 5040 Block_size=VAL(Line$[23,28]) 5042 Hblock_size=VAL(Line$[29,34]) 5044 IF Var_number<0 OR Var_number>32767 THEN GOTO Icode_info_bad 5046 IF Block_size<0 THEN GOTO Icode_info_bad 5048 IF Hblock_size<0 THEN Icode_info_bad 5050 IF Block_type=1 OR Block_type=2 THEN 5052 OFF ERROR 5054 IF Block_type=1 THEN 5056 Temp$=FNHw_cmd_rsp$("NEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3) 5058 ELSE 5060 Temp$=FNHw_cmd_rsp$("SNEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3) 5062 END IF 5064 IF FNHw_io_error THEN GOTO Icode_hw_io_err 5066 ON ERROR GOTO Icode_info_bad 5068 Block_id=VAL(Temp$) 5070 IF Block_id=-1 THEN GOTO Icode_id_bad 5072 IF Block_id>32767 THEN GOTO Icode_info_bad 5074 Info$(I)[35,39]=VAL$(Block_id) 5076 ELSE 5078 Block_id=VAL(Info$(I)[35,39]) 5080 END IF 5082 Var_base=Var_number*2 5084 ON ERROR GOTO Icode_obj_bad 5086 Object(Var_base)=0 5088 Object(Var_base+1)=Block_id 5090 IF Hblock_size>0 THEN 5092 Object(Var_base+2)=0 5094 Object(Var_base+3)=Block_id+1 5096 END IF 5098 END IF 5100 NEXT I 5102 END IF 5104 ! 5106 OFF ERROR 5108 Temp$=FNHw_cmd_rsp$("NEW "&VAL$(SIZE(Object,1))&";NEW?",3) 5110 IF FNHw_io_error THEN GOTO Icode_hw_io_err 5112 Prog_id=VAL(Temp$) 5114 IF Prog_id=-1 THEN 5116 Error_string$="Can not allocate program block" 5118 GOTO Icode_dld_err 5120 END IF 5122 ! 5124 Hw_write_blk(Prog_id,Object(*),5) 5126 IF FNHw_io_error THEN GOTO Icode_hw_io_err 5128 ! 5130 IF Enable_info THEN 5132 Info$(0)[6,10]=VAL$(Prog_id) 5134 END IF 5136 ! 5138 RETURN Prog_id 5140 ! 5142 IF 0 THEN 5144 Icode_obj_bad:! 5146 Error_string$="Object(*) access error" 5148 GOTO Icode_dld_err 5150 Icode_id_bad:! 5152 Error_string$="Could not allocate block data block" 5154 GOTO Icode_dld_err 5156 Icode_hw_io_err:! 5158 Error_string$="Hardware I/O timeout error" 5160 GOTO Icode_dld_err 5162 Icode_info_bad:! 5164 Error_string$="Info$ array format error" 5166 GOTO Icode_dld_err 5168 Icode_dld_err:OFF ERROR 5170 Icode_exec_err("Icode_dld: "&Error_string$) 5172 RETURN -1 5174 END IF 5176 FNEND 5178 ! 5180 Icode_ext_id:DEF FNIcode_ext_id(Block_name$,Info$(*)) 5182! 5184! This function is used to get the id of an ICODE defined block. Since 5186! auto allocate blocks are not allocated until download time, this function 5188! will not return valid data until the ICODE program has been downloaded. 5190! The block name is specified by <Block_name$> and the block id is returned 5192! in the function result. If there is an error (block not allocated yet, 5194! etc), then -1 will be returned. 5196! 5198 DIM Error_string$[100] 5200 IF FNIcode_info_ok(Info$(*),Error_string$) THEN 5202 Info_pos=VAL(Info$(1)[1,5]) 5204 Info_max=Info_pos+VAL(Info$(1)[6,10])-1 5206 Block_name$=UPC$(TRIM$(Block_name$)) 5208 WHILE Info_pos<=Info_max 5210 IF Block_name$[1;1]="^" THEN 5212 IF Block_name$[2]=TRIM$(Info$(Info_pos)[1,16]) THEN 5214 IF VAL(Info$(Info_pos)[29,34])>0 THEN 5216 Auto_id=VAL(Info$(Info_pos)[35,39]) 5217 RETURN Auto_id 5219 ELSE 5220 Icode_exec_err("Icode_ext_id: No header block allocated") 5222 RETURN -1 5224 END IF 5226 END IF 5228 ELSE 5230 IF Block_name$=TRIM$(Info$(Info_pos)[1,16]) THEN 5232 Auto_id=VAL(Info$(Info_pos)[35,39]) 5234 RETURN Auto_id 5236 END IF 5238 END IF 5240 Info_pos=Info_pos+1 5242 END WHILE 5244 ELSE 5246 Icode_exec_err("Icode_ext_id: "&Error_string$) 5248 RETURN -1 5250 END IF 5252 RETURN -1 5254 FNEND 5256 ! 5258 Icode_info_ok:DEF FNIcode_info_ok(Info$(*),Error_string$) 5260! 5262! This function is used (not by the assembler) to see if the Info$ array 5264! is of the correct format. This routine is here because every ICODE 5266! file subprogram that accesses <Info$> needs to make sure that it does 5268! not bomb out because the user didn't pass in the correct array. 5270! Returned in the function result is a 1 if <Info$> seems ok. If a 5272! problem is found with <Info$> then <Error_string$> is used to return 5274! an error string. 5276! 5278 DIM Line$[40] 5280 ! 5282 Error_string$="" 5284 ! 5286 IF BASE(Info$,1)<>0 THEN ! Check index 5288 Error_string$="Info$ index must start at zero" 5290 RETURN 0 5292 END IF 5294 ! 5296 ON ERROR GOTO Icode_str_smal 5298 Line$[1;40]=Info$(0) ! make sure 40 chars wide 5300 Info$(0)=RPT$(" ",40) 5302 Info$(0)=Line$ 5304 ! 5306 ! Check info_info field 5308 ! 5310 ON ERROR GOTO Icode_info_bad 5312 Info_info=VAL(Line$[1,5]) 5314 IF Info_info<0 OR Info_info>2 THEN GOTO Icode_info_bad 5316 ! 5318 Header_size_chk=VAL(Info$(0)[11,15]) ! get header size 5320 ! 5322 ! Now see if size make sense. 5324 ! 5326 Total_size=VAL(Info$(0)[16,20]) 5328 IF SIZE(Info$,1)<Header_size_chk OR SIZE(Info$,1)<Total_size THEN 5330 Error_string$="Info$ format error - Info$ too small" 5332 RETURN 0 5334 END IF 5336 ! 5338 RETURN 1 5340 ! 5342 IF 0 THEN 5344 Icode_info_bad:Error_string$="Info$ format error" 5346 RETURN 0 5348 Icode_str_smal:Error_string$="Info$ format error - < 40 chars" 5350 RETURN 0 5352 END IF 5354 FNEND 5356 ! 5358 Icode_exec_err:SUB Icode_exec_err(Error_string$) 5360! 5362! This function is used to display an error message on the screen. 5364! The screen is cleared, the error message is displayed, this routine 5366! then waits 3 seconds and returns. 5368! 5370 BEEP 5372 OUTPUT CRT;"" 5374 OUTPUT CRT 5376 OUTPUT CRT;"*** ";Error_string$;" ***" 5378 OUTPUT CRT 5380 WAIT 3 5382 SUBEND 5384 ! 5386 Icode_def_ext:DEF FNIcode_def_ext(Block_name$,Use_main_ram,Block_size,Hblock_size,Block_id,Info$(*)) 5388! 5390! This function is used to bind a DEFBLK_EXT block name with a block id. 5392! The block to be bound is specified by <Block_name$>. If the block is 5394! an HP3565S HP-IB module MAIN data RAM block, then <Use_main_ram> should 5396! be non-zero. If the block is to reside in SP data RAM, then 5398! <Use_main_ram> should be zero. <Info$(*)> is the information array 5400! that was filled with all sorts of information from the assembler. There 5402! are two modes this function can be used in. If <Block_id> is <= 0 5404! then mode 1 is used. In mode 1, <Block_size> and <Hblock_size> define 5406! the sizes of the data block and header data block. These blocks will 5408! be allocated for the user by the downloader (FNIcode_dld). 5410! If <block_id> > 0 then mode 2 is used. In mode 2, the user has already 5412! allocated the block and is just telling the downloader what the 5414! block id is. In mode 2, <Block_size> and <Hblock_size> must also 5416! contain the size of the data block and header block. In either 5418! case, the function result will be the block id of block specified. 5420! If an error occurs during the execution of this function, then an 5422! error message is displayed, and a -1 is returned as the function 5424! result. Note that this function should be used after the program is 5426! is assembled and before the program is downloaded. 5428! 5430 DIM Line$[40],Error_string$[40] 5432 INTEGER Found_match 5434 IF LEN(Block_name$)>16 THEN 5436 Icode_exec_err("Icode_def_ext: Block_name$ parameter string too long") 5438 RETURN -1 5440 END IF 5442 IF Block_size<0 THEN 5444 Icode_exec_err("Icode_def_ext: Invalid Block_size parameter") 5446 RETURN -1 5448 END IF 5450 IF Hblock_size<0 THEN 5452 Icode_exec_err("Icode_def_ext: Invalid header block size parameter") 5454 RETURN -1 5456 END IF 5458 IF Block_id<0 THEN 5460 Icode_exec_err("Icode_def_ext: Invalid Block_id parameter") 5462 RETURN -1 5464 END IF 5466 IF FNIcode_info_ok(Info$(*),Error_string$) THEN 5468 Block_name$=UPC$(TRIM$(Block_name$)) 5470 Info_pos=VAL(Info$(1)[1,5]) 5472 Info_max=Info_pos+VAL(Info$(1)[6,10]) 5474 Found_match=0 5476 WHILE Info_pos<Info_max AND NOT Found_match 5478 IF Block_name$=TRIM$(Info$(Info_pos)[1,16]) THEN 5480 Found_match=1 5482 IF Block_id=0 THEN 5484 IF Use_main_ram THEN 5486 Temp$=FNHw_cmd_rsp$("NEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3) 5488 ELSE 5490 Temp$=FNHw_cmd_rsp$("SNEW "&VAL$(Block_size)&","&VAL$(Hblock_size)&";NEW?",3) 5492 END IF ! Use_main_ram 5494 IF FNHw_io_error THEN 5496 Icode_exec_err("Icode_def_ext: I/O error on block allocation") 5498 RETURN -1 5500 ELSE 5502 Block_id=VAL(Temp$) 5504 IF Block_id=-1 THEN 5506 Icode_exec_err("Icode_def_ext: HP-IB module won't allocate block") 5508 RETURN -1 5510 END IF 5512 Line$=Info$(Info_pos) 5514 IF Use_main_ram THEN 5516 Line$[17;1]="3" 5518 ELSE 5520 Line$[17;1]="4" 5522 END IF 5524 IF Line$[17;1]="1" OR Line$[17;1]="2" THEN 5526 Icode_exec_err("Icode_def_ext: Can't redefine auto allocate blocks") 5528 RETURN -1 5530 END IF 5532 END IF 5534 ELSE 5536 Line$=Info$(Info_pos) 5538 IF Line$[17;1]="1" OR Line$[17;1]="2" THEN 5540 Icode_exec_err("Icode_def_ext: Can't redefine auto allocate blocks") 5542 RETURN -1 5544 ELSE 5546 IF Use_main_ram THEN 5548 Line$[17;1]="3" 5550 ELSE 5552 Line$[17;1]="4" 5554 END IF 5556 END IF 5558 END IF ! IF Block_id<=0 5560 Line$[23,28]=VAL$(Block_size) 5562 Line$[29,34]=VAL$(Hblock_size) 5564 Line$[35,39]=VAL$(Block_id) 5566 Info$(Info_pos)=Line$ 5568 END IF 5570 Info_pos=Info_pos+1 5572 END WHILE 5574 IF NOT Found_match THEN 5576 Icode_exec_err("Icode_def_ext: Undefined Block_name - '"&Block_name$&"'") 5578 RETURN -1 5580 END IF 5582 ELSE 5584 Icode_exec_err("Icode_def_ext: "&Error_string$) 5586 RETURN -1 5588 END IF 5590 RETURN Block_id 5592 FNEND ! Icode_def_ext 5594 ! 5596 Icode_debug:SUB Icode_debug(INTEGER Debug_mode,Info$(*),OPTIONAL Source$(*)) 5598! 5600! This subprogram is used to HELP debug an ICODE program. With this 5602! debugger the user can trace program execution, examine data blocks, 5604! set break points, single step, examine source code, and activate the 5606! command interpreter in the DIAG file. <Debug_mode> is an input 5608! parameter that determines when and if the debugger should enter an 5610! interactive debug mode. If <Debug_mode> = 0 then the debugger will 5612! enter interactive debug mode if the ICODE program is not running or 5614! is paused. Otherwise, the debugger will exit. If <Debug_mode> = 1, 5616! then the debugger will wait until the ICODE program is not running 5618! or is paused, then it will enter an interactive debug mode. If 5620! <Debug_mode> = 2 then the debugger will immediately enter an interactive 5622! debug mode. Once in interactive mode, the debugger is exited through 5624! a soft key. <Info$> must be present. <Source$> is an optional 5626! parameter which, when present, must contain the original source code. 5628! 5630! NOTE: For information on format of Info$ array, see ICODE assembler 5632! Icode_fill_info routine. 5634! 5636! 5638! The best way to learn about the debugger is to use it. Notice I didn't 5640! say that its operation was obvious. The following are some special 5642! notes that are not obvious: 5644! + If the debugger can detect an error before talking with the 5646! hardware, then an error message is displayed and execution 5648! continues. If an error is detected by the hardware, then an 5650! error message is displayed, and the BASIC program paused. When 5652! continued, the BASIC program (debugger) will exit. 5654! + In source display mode, lines may be specified by line number or by 5656! label. Also, there are some pre-defined labels that refer to the 5658! first line ('START' or 'BEGIN') and the last line ('STOP' or 'END'). 5660! + Only one break point may be set at one time. 5662! + Single stepping clears a previously set break point. 5664! + If a break point is set for line x, then the ICODE program will 5666! break just before line x is executed. 5668! + To specify a block, the name or block id may be used. 5670 ! 5672 INTEGER Info_info,Prog_id,Obj_size 5674 INTEGER Null_flag,Error_flag,X_disp_count,Disp_cnt,Count 5676 INTEGER S_height,S_width,S_disp_height,Icode_inactive,Icode_paused 5678 REAL I 5680 DIM Error_string$[100] 5682 DIM Ver_str$[50],Mode_str$[80],Temp$[255],State_str$[20] 5684 INTEGER Temp_int,Int_temp 5686 REAL Temp_real,Real_temp 5688 ! 5690 ! Initialize display line stuff 5692 ! 5694 OUTPUT CRT 5696 Ver_str$="ICODE Dbgr. Ver 1.0 " 5698 DISP Ver_str$;" Initializing." 5700 ! 5702 ! Deal with Debug_mode 5704 ! 5706 SELECT Debug_mode 5708 CASE 0 5710 GOSUB Icode_state 5712 IF NOT Icode_inactive AND NOT Icode_paused THEN SUBEXIT 5714 GOSUB Icode_do_debug 5716 CASE 1 5718 GOSUB Icode_state 5720 IF NOT Icode_inactive AND NOT Icode_paused THEN DISP Ver_str$&" Waiting for ICODE to pause" 5722 GOSUB Icode_wait_paus 5724 GOSUB Icode_do_debug 5726 CASE 2 5728 GOSUB Icode_do_debug 5730 CASE ELSE 5732 Error_string$="Invalid Debug_mode value" 5734 GOTO Icode_dbg_err 5736 END SELECT 5737 GOTO Icode_dbg_exit ! clean up Info$(*) stuff and get out 5739 ! 5740 ! This routine is used to wait until the ICODE program is paused or 5742 ! not running. 5744 ! 5746 Icode_wait_paus:! 5748 INTEGER First_flag 5750 First_flag=1 5752 REPEAT 5754 IF NOT First_flag THEN WAIT .8 ! don't want HP-IB module spending 5756 First_flag=0 ! all its time responding to queries 5758 GOSUB Icode_state 5760 UNTIL Icode_inactive OR Icode_paused 5762 RETURN 5764 ! 5766 ! Output: Icode_inactive and Icode_paused 5768 ! 5770 ! This routine is used to get the current ICODE program state. If 5772 ! the ICODE program is currently not running, then Icode_inactive is 5774 ! set to 1, otherwise 0. If the ICODE program is currently paused, 5776 ! then Icode_paused is set to 1, otherwise 0. Note that the state 5778 ! of the ICODE program can change between the time this routine is 5780 ! called and the time the caller acts on the info returned by this 5782 ! routine. 5784 ! 5786 Icode_state:! 5788 DIM Hpib_stat_str$[50] 5790 WAIT .2 5792 Temp$=FNHw_cmd_rsp$("STC?",5) 5794 IF FNHw_io_error THEN 5796 Error_string$="Hardware I/O timeout error" 5798 GOTO Icode_dbg_err 5800 END IF 5802 Hpib_stat_str$=FNHw_stat_2_str$(VAL(Temp$)) 5804 Icode_inactive=POS(Hpib_stat_str$,"PRG")<>0 5806 Icode_paused=POS(Hpib_stat_str$,"UPP")<>0 5808 RETURN 5810 ! 5812 ! This routine is used to exit the debugger 5814 ! 5816 Icode_dbg_exit:! 5818 GOSUB Icode_put_ihist ! put history back in Info$(*) 5820 GOSUB Icode_put_ibkpt ! put break point info back in Info$(*) 5822 SUBEXIT 5824 ! 5826 ! Output: State_str$ 5828 ! 5830 ! This routine is used to get a string that indicates the state of 5832 ! the ICODE program. 5834 ! 5836 Icode_state_str:! 5838 GOSUB Icode_state 5840 IF Icode_paused THEN 5842 State_str$="ICODE paused." 5844 ELSE 5846 IF Icode_inactive THEN 5848 State_str$="ICODE inactive." 5850 ELSE 5852 State_str$="ICODE running." 5854 END IF 5856 END IF 5858 RETURN 5860 ! 5862 ! ********************** Interactive Debug Loop ****************** 5864 ! 5866 ! This is the main interactive debug loop. It prompts the user to 5868 ! select which mode the user wishes to enter. The functions at 5870 ! this main level are as follows: 5872 ! 1 - Go into variable menu. 5874 ! 2 - Go into data block menu. 5876 ! 3 - Go into source code menu. 5878 ! 4 - Display ICODE execution history. 5880 ! 5 - Go into ICODE program control menu. 5882 ! 6 - Go into DIAG command interpreter. 5884 ! 7 - CONTinue ICODE program. 5886 ! 8 - Return from debugger 5888 ! 5890 INTEGER Debug_loop_done 5892 ! 5894 Icode_do_debug:! 5896 GOSUB Icode_dbg_init 5898 Debug_loop_done=0 5900 REPEAT 5902 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 5904 ON KEY 1 LABEL FNUser_keylabel$("Vars") CALL User_key1isr 5906 ON KEY 2 LABEL FNUser_keylabel$("Blocks") CALL User_key2isr 5908 ON KEY 3 LABEL FNUser_keylabel$("Source") CALL User_key3isr 5910 ON KEY 4 LABEL FNUser_keylabel$("History") CALL User_key4isr 5912 ON KEY 5 LABEL FNUser_keylabel$("Prgm Cntrl") CALL User_key5isr 5914 ON KEY 6 LABEL FNUser_keylabel$("Cmnd Intrp") CALL User_key6isr 5916 ON KEY 7 LABEL FNUser_keylabel$("Cont") CALL User_key7isr 5918 ON KEY 8 LABEL FNUser_keylabel$("Exit") CALL User_key8isr 5920 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 5922 REPEAT 5924 GOSUB Icode_state_str ! Get State_str$ 5926 Mode_str$=Ver_str$&" "&State_str$&" MAIN menu. Enter softkey." 5928 DISP Mode_str$ 5930 UNTIL FNUser_key_press 5932 SELECT FNUser_get_key 5934 CASE 1 ! Variable mode 5936 GOSUB Icode_vars 5938 CASE 2 ! Display block mode 5940 GOSUB Icode_blks 5942 CASE 3 ! Display source code mode 5944 GOSUB Icode_src 5946 CASE 4 ! Display ICODE execution history 5948 GOSUB Icode_hist 5950 CASE 5 ! ICODE program control mode 5952 GOSUB Icode_trc 5954 CASE 6 5956 Diag_comint ! Diagnostics Command Interpreter 5958 CASE 7 5960 GOSUB Icode_cont ! CONTinue ICODE program 5962 CASE 8 5964 Debug_loop_done=1 ! Exit debugger 5966 END SELECT 5968 UNTIL Debug_loop_done 5972 DISP 5974 RETURN 5976 ! 5978 ! ********************** Variable mode ******************************* 5980 ! 5982 ! This section handles all variable functions. The user is prompted 5984 ! to select a variable function. The functions at this level are as 5986 ! follows: 5988 ! 1 - Display all variables. If the variables require more than 5990 ! one screen full, then go into full screen mode. 5992 ! 2 - Display some variables. User specifies start variable 5994 ! and count. 5996 ! 3 - Modify variable. User specifies variable name and new 5998 ! value. 6000 ! 4 - Undefined. 6002 ! 5 - Toggle variable display mode between decimal and hex. 6004 ! 6 - Undefined. 6006 ! 7 - Undefined. 6008 ! 8 - Return to main menu. 6010 ! 6012 INTEGER Done_vars_loop,Disp_vars_hex 6014 INTEGER Var_disp_strt,Var_disp_cnt,Var_disp_last,Var_disp_ptr 6016 INTEGER Var_info_strt,Var_info_last,Var_info_cnt,Vars_allocated 6018 INTEGER Var_num,Var_ptr,Var_set_value 6020 INTEGER Int_hi,Int_lo 6022 REAL Var_val 6024 DIM Var_name$[20] 6026 ! 6028 Icode_vars:! 6030 IF Var_info_cnt=0 THEN 6032 BEEP 6034 DISP " ***** No variables to operate on *****" 6036 WAIT 3 6038 ELSE 6040 Done_vars_loop=0 6042 REPEAT 6044 ON KEY 1 LABEL FNUser_keylabel$("Disp All") CALL User_key1isr 6046 ON KEY 2 LABEL FNUser_keylabel$("Disp Some") CALL User_key2isr 6048 ON KEY 3 LABEL FNUser_keylabel$("Modify") CALL User_key3isr 6050 ON KEY 4 LABEL FNUser_keylabel$("") CALL User_key4isr 6052 IF Disp_vars_hex THEN 6054 ON KEY 5 LABEL FNUser_keylabel$("Decimal") CALL User_key5isr 6056 ELSE 6058 ON KEY 5 LABEL FNUser_keylabel$("Hex") CALL User_key5isr 6060 END IF 6062 ON KEY 6 LABEL FNUser_keylabel$("") CALL User_key6isr 6064 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 6066 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 6068 REPEAT 6070 GOSUB Icode_state_str 6072 Mode_str$=Ver_str$&" "&State_str$&" VARIABLE menu." 6074 DISP Mode_str$&" Enter softkey." 6076 UNTIL FNUser_key_press 6078 SELECT FNUser_get_key 6080 CASE 1 ! disp all vars 6082 GOSUB Icode_all_vars 6084 CASE 2 ! disp some vars 6086 GOSUB Icode_some_vars 6088 CASE 3 ! modify var 6090 GOSUB Icode_mod_var 6092 CASE 4 6094 CASE 5 ! toggle variable display mode 6096 Disp_vars_hex=NOT Disp_vars_hex 6098 CASE 6,7 6100 CASE 8 ! Return to main menu 6102 Done_vars_loop=1 6104 END SELECT 6106 UNTIL Done_vars_loop 6108 END IF 6110 RETURN 6112 ! 6114 ! This routine is used if the user only wants to display a small 6116 ! number of variables on the screen at once. This may be useful 6118 ! if the user wishes to look at two types of information on the 6120 ! same screen at once. 6122 ! 6124 Icode_some_vars:! 6126 Mode_str$=Ver_str$&" VARIABLE disp mode." 6128 ! 6130 CALL Icode_inpt_str(Mode_str$&" Enter start variable name:",Var_name$) 6132 IF Var_name$="" THEN RETURN 6134 ! 6136 GOSUB Icode_scan_vars ! uses Var_name$, returns Var_ptr 6138 IF Var_ptr=0 THEN 6140 BEEP 6142 DISP "***** Undefined variable reference - '"&Var_name$&"' *****" 6144 WAIT 3 6146 RETURN 6148 END IF 6150 ! 6152 CALL Icode_inpt_num(Mode_str$&" Enter # of variables to disp:",Var_disp_cnt,Null_flag,Error_flag) 6154 ! 6156 IF Null_flag OR Error_flag THEN RETURN 6158 ! 6160 IF Var_ptr+Var_disp_cnt>Var_info_strt+Var_info_cnt THEN 6162 BEEP 6164 DISP "***** variable display count too large *****" 6166 WAIT 3 6168 ELSE 6170 Var_disp_strt=Var_ptr 6172 Var_disp_stop=Var_disp_strt+Var_disp_cnt-1 6174 GOSUB Icode_disp_vars ! pass Var_disp_strt and Var_disp_stop 6176 END IF 6178 RETURN 6180 ! 6182 ! This routine is used to modify a variable. The user must specify 6184 ! a variable name and its new value. 6186 ! 6188 Icode_mod_var:! 6190 GOSUB Icode_state ! returns Icode_inactive & Icode_paused 6192 IF NOT Icode_inactive AND NOT Icode_paused THEN 6194 BEEP 6196 DISP "***** Can't modify variables while ICODE running *****" 6198 WAIT 3 6200 RETURN 6202 END IF 6204 ! 6206 Mode_str$=Ver_str$&" VARIABLE modify mode." 6208 CALL Icode_inpt_str(Mode_str$&" Enter variable name:",Var_name$) 6210 ! 6212 IF Var_name$="" THEN RETURN 6214 ! 6216 GOSUB Icode_scan_vars ! returns Var_ptr from Var_name$ 6218 IF Var_ptr=0 THEN 6220 BEEP 6222 DISP "***** Undefined variable reference - '"&Var_name$&"' *****" 6224 WAIT 3 6226 RETURN 6228 END IF 6230 ! 6232 CALL Icode_inpt_num(Mode_str$&" Enter variable value:",Var_set_value,Null_flag,Error_flag) 6234 IF Error_flag THEN RETURN 6236 IF Null_flag THEN 6238 OUTPUT CRT 6240 OUTPUT CRT;"NO variables modified." 6242 ELSE 6244 GOSUB Icode_r_varvals ! read variables out of ICODE program 6246 ! 6248 Var_num=VAL(Info$(Var_ptr)[17,21]) ! get variable number from Info$ 6250 ! 6252 OUTPUT CRT 6254 IF Disp_vars_hex THEN 6256 OUTPUT CRT;"$";DVAL$(Var_set_value,16);" ==> ";TRIM$(Var_name$) 6258 ELSE 6260 OUTPUT CRT;Var_set_value;" ==> ";TRIM$(Var_name$) 6262 END IF 6264 ! 6266 CALL Lib_32_to_16((Var_set_value),Int_hi,Int_lo) 6268 Var_values(Var_num*2)=Int_hi 6270 Var_values(Var_num*2+1)=Int_lo 6272 ! 6274 GOSUB Icode_w_varvals ! restore var values to ICODE program 6276 END IF 6278 RETURN 6280 ! 6282 ! Input: Var_name$ Output: Var_ptr 6284 ! 6286 ! This routine is used to search though Info$ and find where 6288 ! <Var_name$> is in Info$. Returned is a pointer into Info$ 6290 ! 6292 Icode_scan_vars:! 6294 Var_name$=UPC$(TRIM$(Var_name$)) 6296 Var_ptr=Var_info_strt-1 6298 Var_info_last=Var_info_strt+Var_info_cnt-1 6300 LOOP 6302 Var_ptr=Var_ptr+1 6304 EXIT IF Var_ptr>Var_info_last 6306 EXIT IF Var_name$=TRIM$(Info$(Var_ptr)[1,16]) 6308 END LOOP 6310 IF Var_ptr>Var_info_last THEN Var_ptr=0 6312 RETURN 6314 ! 6316 ! This routine is used to display all variables. First it sees if 6318 ! all the variables will fit on one screen. If they will, then the 6320 ! display routine is called to display all the variables. If all 6322 ! variables will not fit on one screen, then a variable display 6324 ! screen mode is entered. 6326 ! 6328 Icode_all_vars: ! Display all variables 6330 INTEGER Done_avars_loop 6332 X_disp_count=S_width DIV 30 6334 S_disp_height=S_height-11 6336 ! 6338 ! Can we fit all variables on the screen at once? 6340 ! 6342 IF X_disp_count*(S_disp_height)>=Var_info_cnt THEN 6344 Var_disp_strt=Var_info_strt ! Yes 6346 Var_disp_stop=Var_info_last 6348 GOSUB Icode_disp_vars 6350 ELSE ! No 6352 ! 6354 ! This is the variable display full screen mode. From here the 6356 ! user can look at any portion of the variable table. 6358 ! 6360 Done_avars_loop=0 6362 GOSUB Icode_win_vars 6364 REPEAT 6366 ON KEY 1 LABEL FNUser_keylabel$("Prev Page") CALL User_key1isr 6368 ON KEY 2 LABEL FNUser_keylabel$("Next Page") CALL User_key2isr 6370 ON KEY 3 LABEL FNUser_keylabel$("Prev Line") CALL User_key3isr 6372 ON KEY 4 LABEL FNUser_keylabel$("Next Line") CALL User_key4isr 6374 ON KEY 5 LABEL FNUser_keylabel$("Begin") CALL User_key5isr 6376 ON KEY 6 LABEL FNUser_keylabel$("End") CALL User_key6isr 6378 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 6380 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 6382 REPEAT 6384 GOSUB Icode_state_str 6386 Mode_str$=Ver_str$&" "&State_str$&" VARIABLE disp menu." 6388 DISP Mode_str$&" Enter softkey." 6390 UNTIL FNUser_key_press 6392 SELECT FNUser_get_key 6394 CASE 1 6396 Var_disp_strt=Var_disp_strt-((S_disp_height-5)*X_disp_count) 6398 GOSUB Icode_win_vars 6400 CASE 2 6402 Var_disp_strt=Var_disp_strt+((S_disp_height-5)*X_disp_count) 6404 GOSUB Icode_win_vars 6406 CASE 3 6408 Var_disp_strt=Var_disp_strt-(X_disp_count) 6410 GOSUB Icode_win_vars 6412 CASE 4 6414 Var_disp_strt=Var_disp_strt+(X_disp_count) 6416 GOSUB Icode_win_vars 6418 CASE 5 6420 Var_disp_strt=Var_info_strt 6422 GOSUB Icode_win_vars 6424 CASE 6 6426 Var_disp_strt=Var_info_last 6428 GOSUB Icode_win_vars 6430 CASE 7 6432 CASE 8 ! Return to main menu 6434 Done_avars_loop=1 6436 END SELECT 6438 UNTIL Done_avars_loop 6440 END IF 6442 RETURN 6444 ! 6446 ! Input: Var_disp_strt 6448 ! 6450 ! This routine is used to select a section of the variable table 6452 ! for display. From <Var_disp_strt> this routine will assign 6454 ! <Var_disp_strt> and <Var_disp_stop> so they point into Info$ to 6456 ! valid variable lines and so they get as many variables on the 6458 ! screen as possible. This routine also calls the display routine. 6460 ! 6462 Icode_win_vars: ! Var_disp_strt is parameter 6464 Var_disp_strt=MAX(Var_info_strt,Var_disp_strt) 6466 Var_disp_strt=MIN(Var_info_last,Var_disp_strt) 6468 Var_disp_stop=MIN(Var_info_last,Var_disp_strt+(S_disp_height*X_disp_count)-1) 6470 IF Var_disp_stop=Var_info_last THEN Var_disp_strt=MAX(Var_info_strt,Var_disp_stop-(S_disp_height*X_disp_count)+1) 6472 User_clr_scr 6474 GOSUB Icode_disp_vars 6476 RETURN 6478 ! 6480 ! Input: Var_disp_strt and Var_disp_stop 6482 ! 6484 ! This routine is used to display a section of the variable table. 6486 ! 6488 Icode_disp_vars:! 6490 IF Var_disp_stop>=Var_disp_strt THEN 6492 GOSUB Icode_r_varvals 6494 Var_disp_cnt=Var_disp_stop-Var_disp_strt+1 6496 OUTPUT CRT 6498 OUTPUT CRT;" >>>> Variable Listing. Listing";Var_disp_cnt;" out of";Var_info_cnt;" <<<<" 6500 X_disp_count=S_width DIV 30 6502 GOSUB Icode_r_varvals 6504 OUTPUT CRT;"|"; 6506 Var_disp_ptr=Var_disp_strt 6508 IF Disp_vars_hex THEN 6510 FOR I=1 TO MIN(X_disp_count,Var_disp_cnt) 6512 OUTPUT CRT USING "#,16A,1X,1X,8A,1A";"Name","Value","|" 6514 NEXT I 6516 OUTPUT CRT 6518 OUTPUT CRT;"|"; 6520 FOR I=1 TO MIN(X_disp_count,Var_disp_cnt) 6522 OUTPUT CRT USING "#,16A,1A,9A,1A";RPT$("-",16),"+",RPT$("-",9),"|" 6524 NEXT I 6526 ELSE 6528 FOR I=1 TO MIN(X_disp_count,Var_disp_cnt) 6530 OUTPUT CRT USING "#,16A,1X,11A,1A";"Name"," Value ","|" 6532 NEXT I 6534 OUTPUT CRT 6536 OUTPUT CRT;"|"; 6538 FOR I=1 TO MIN(X_disp_count,Var_disp_cnt) 6540 OUTPUT CRT USING "#,16A,1A,11A,1A";RPT$("-",16),"+",RPT$("-",11),"|" 6542 NEXT I 6544 END IF 6546 OUTPUT CRT 6548 WHILE Var_disp_ptr<=Var_disp_stop 6550 OUTPUT CRT;"|"; 6552 FOR I=1 TO X_disp_count 6554 IF Var_disp_ptr<=Var_disp_stop THEN 6556 Var_num=VAL(Info$(Var_disp_ptr)[17,21]) 6558 Int_hi=Var_values(Var_num*2) 6560 Int_lo=Var_values(Var_num*2+1) 6562 CALL Lib_16_to_32(Int_hi,Int_lo,Var_val) 6564 IF Disp_vars_hex THEN 6566 OUTPUT CRT USING "#,16A,1X,1A,8A,1A";Info$(Var_disp_ptr)[1,16];"$";DVAL$(Var_val,16),"|" 6568 ELSE 6570 OUTPUT CRT USING "#,16A,1X,11D,1A";Info$(Var_disp_ptr)[1,16],Var_val,"|" 6572 END IF 6574 Var_disp_ptr=Var_disp_ptr+1 6576 END IF 6578 NEXT I 6580 OUTPUT CRT 6582 END WHILE 6584 END IF 6586 RETURN 6588 ! 6590 ! This routine is used to read all variable values form the ICODE 6592 ! program. 6594 ! 6596 Icode_r_varvals:! 6598 Hw_read_blk((Prog_id),Var_values(*),5) 6600 GOSUB Icode_hw_err_ck 6602 RETURN 6604 ! 6606 ! This routine is used to restore all variable values to the ICODE 6608 ! program. 6610 ! 6612 Icode_w_varvals:! 6614 Hw_write_blk((Prog_id),Var_values(*),5) 6616 GOSUB Icode_hw_err_ck 6618 RETURN 6620 ! 6622 ! This routine is used to initialize the variable section of the 6624 ! debugger. 6626 ! 6628 Icode_vars_init:! 6630 Disp_vars_hex=VAL(Info$(5)[11;1]) ! disp in hex or decimal 6632 ! 6634 ! Get info on variable table in Info$(*) 6636 ! 6638 Var_info_strt=VAL(Info$(4)[1,5]) 6640 Var_info_cnt=VAL(Info$(4)[6,10]) 6642 Var_info_last=Var_info_strt+Var_info_cnt-1 6644 ! 6646 ! Need array to store variable in 6648 ! 6650 Vars_allocated=VAL(Info$(0)[21,25]) 6652 ALLOCATE INTEGER Var_values(0:(Vars_allocated*2)-1) 6654 ! 6656 RETURN 6658 ! 6660 ! *************************** Begin Blocks ********************** 6662 ! 6664 ! This section of the debugger enables the user to examine the 6666 ! list of data blocks, or the data blocks themselves. 6668 ! 1 - Display block. 6670 ! 2 - Display block names and block id's. 6672 ! 3 - 6674 ! 4 - 6676 ! 5 - 6678 ! 6 - 6680 ! 7 - 6682 ! 8 - Return to main menu. 6684 ! 6686 INTEGER Done_blks_loop,Block_id,Disp_blks_form,Blk_ptr,Key_pressed 6688 INTEGER Blk_disp_strt,Blk_disp_cnt,Blk_disp_stop,Blk_infostrt,Blk_infolast 6690 INTEGER Blkext_infostrt,Blkext_infocnt,Blkext_infolast 6692 INTEGER Blkvar_infostrt,Blkvar_infocnt,Blkvar_infolast 6694 INTEGER Blkcon_infostrt,Blkcon_infocnt,Blkcon_infolast 6696 INTEGER Block_addr,Block_offset,Block_disp_cnt,Block_ptr,Not_a_num_flag 6698 DIM Block_name$[20] 6700 ! 6702 Icode_blks:! 6704 Done_blks_loop=0 6706 REPEAT 6708 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 6710 ON KEY 1 LABEL FNUser_keylabel$("Disp Block") CALL User_key1isr 6712 ON KEY 2 LABEL FNUser_keylabel$("Block Names") CALL User_key2isr 6714 ON KEY 3 LABEL FNUser_keylabel$("") CALL User_key3isr 6716 ON KEY 4 LABEL FNUser_keylabel$("Full Screen") CALL User_key4isr 6718 SELECT Disp_blks_form 6720 CASE 0 ! currently in decimal 6722 ON KEY 5 LABEL FNUser_keylabel$("Hex") CALL User_key5isr 6724 ON KEY 6 LABEL FNUser_keylabel$("Float") CALL User_key6isr 6726 CASE 1 ! currently in hex 6728 ON KEY 5 LABEL FNUser_keylabel$("Decimal") CALL User_key5isr 6730 ON KEY 6 LABEL FNUser_keylabel$("Float") CALL User_key6isr 6732 CASE 2 ! currently in floating point 6734 ON KEY 5 LABEL FNUser_keylabel$("Decimal") CALL User_key5isr 6736 ON KEY 6 LABEL FNUser_keylabel$("Hex") CALL User_key6isr 6738 END SELECT 6740 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 6742 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 6744 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 6746 REPEAT 6748 GOSUB Icode_state_str 6750 Mode_str$=Ver_str$&" "&State_str$&" BLOCK menu." 6752 DISP Mode_str$;" Enter softkey." 6754 UNTIL FNUser_key_press 6756 SELECT FNUser_get_key 6758 CASE 1 6760 GOSUB Icode_disp_ublk ! display user specified block 6762 CASE 2 6764 Blk_disp_strt=Blkext_infostrt 6766 IF Blk_disp_strt=0 THEN Blk_disp_strt=Blkvar_infostrt 6768 IF Blk_disp_strt=0 THEN Blk_disp_strt=Blkcon_infostrt 6770 Blk_disp_cnt=Blkext_infocnt+Blkvar_infocnt+Blkcon_infocnt 6772 GOSUB Icode_list_blks 6774 CASE 3 6776 CASE 4 6778 GOSUB Icode_fs_blk 6780 CASE 5 6782 Key_pressed=5 6784 GOSUB Icode_blks_newf 6786 CASE 6 6788 Key_pressed=6 6790 GOSUB Icode_blks_newf 6792 CASE 7 6794 CASE 8 6796 Done_blks_loop=1 6798 END SELECT 6800 UNTIL Done_blks_loop 6802 RETURN 6804 ! 6806 ! This routine is used to display a block. The user must specify 6808 ! a block name (or id), an offset into the block, and a count. Now, 6810 ! the section of the block specified by the user is displayed on the 6812 ! CRT There is no scrolling. This should be changed. 6814 ! 6816 Icode_disp_ublk: ! display user specified block 6818 ! 6820 ! Get block name 6822 ! 6824 Mode_str$=Ver_str$&" "&State_str$&" Disp BLOCK menu." 6826 Icode_inpt_num(Mode_str$&" Enter disp block name:",Block_id,Null_flag,Error_flag,Block_name$) 6828 ! 6830 ! If numerical value was entered, then it must have been a block id 6832 ! else it must have been a block name. 6834 ! 6836 IF Block_name$="" THEN 6838 IF Null_flag OR Error_flag THEN RETURN !return on null entry 6840 IF Block_id<=0 OR Block_id>=32767 THEN 6842 BEEP 6844 DISP "***** Invalid block id entry *****" 6846 WAIT 3 6848 RETURN 6850 END IF 6852 Block_name$=VAL$(Block_id) ! need this for disp header. 6854 ELSE 6856 GOSUB Icode_blk_ptr ! returns Blk_ptr from Block_name$ 6858 IF Blk_ptr=-1 THEN RETURN 6860 GOSUB Icode_blk_id ! returns Block_id from Blk_ptr 6862 END IF 6864 ! 6866 ! Now get block offset 6868 ! 6870 Icode_inpt_num(Mode_str$&" Enter disp block offset:",Block_offset,Null_flag,Error_flag) 6872 IF Block_offset<0 OR Block_offset>=32767 THEN 6874 BEEP 6876 DISP "***** Invalid Block_offset parameter *****" 6878 WAIT 3 6880 RETURN 6882 END IF 6884 ! 6886 IF Null_flag OR Error_flag THEN RETURN 6888 ! 6890 ! Now get block disp count 6892 ! 6894 Icode_inpt_num(Mode_str$&" Enter disp count:",Block_disp_cnt,Null_flag,Error_flag) 6896 IF Null_flag OR Error_flag OR Block_disp_cnt=0 THEN RETURN 6898 IF Block_disp_cnt<0 OR Block_disp_cnt>32767 THEN 6900 BEEP 6902 DISP "***** Invalid Block_count parameter *****" 6904 WAIT 3 6906 RETURN 6908 END IF 6910 Block_size=Block_disp_cnt 6912 ! 6914 ! 4 words per point if display form is floating point 6916 ! 6918 IF Disp_blks_form=2 THEN Block_size=Block_size*4 6920 Block_size=Block_size+Block_offset 6922 IF Block_size>32767 THEN 6924 BEEP 6926 DISP "***** Too many words to read back from HP-IB module *****" 6928 WAIT 3 6930 RETURN 6932 END IF 6934 ! 6936 ! Lets get the block from the hardware 6938 ! 6940 ALLOCATE INTEGER Block(0:Block_size-1) 6942 DISP "Getting block ..." 6944 Hw_read_blk((Block_id),Block(*),5) ! get block from HP-IB module 6946 IF FNHw_io_error THEN 6948 BEEP 6950 DISP "***** Unable to read block from hardware *****" 6952 WAIT 3 6954 ELSE 6956 GOSUB Icode_disp_blk ! display block 6958 END IF 6960 ! 6962 DEALLOCATE Block(*) 6964 RETURN 6966 ! 6968 Icode_fs_blk:! 6970 ! 6972 ! Get block name 6974 ! 6976 Mode_str$=Ver_str$&" "&State_str$&" Disp BLOCK menu." 6978 Icode_inpt_num(Mode_str$&" Enter disp block name:",Block_id,Null_flag,Error_flag,Block_name$) 6980 ! 6982 ! If numerical value was entered, then it must have been a block id 6984 ! else it must have been a block name. 6986 ! 6988 IF Block_name$="" THEN 6990 IF Null_flag OR Error_flag THEN RETURN !return on null entry 6992 IF Block_id<=0 OR Block_id>=32767 THEN 6994 BEEP 6996 DISP "***** Invalid block id entry *****" 6998 WAIT 3 7000 RETURN 7002 END IF 7004 Block_name$=VAL$(Block_id) ! need this for disp header. 7006 ELSE 7008 GOSUB Icode_blk_ptr ! returns Blk_ptr from Block_name$ 7010 IF Blk_ptr=-1 THEN RETURN 7012 GOSUB Icode_blk_id ! returns Block_id from Blk_ptr 7014 END IF 7016 ! 7018 ! Now get block size 7020 ! 7022 Icode_inpt_num(Mode_str$&" Enter block size:",Int_temp,Null_flag,Error_flag) 7024 IF Null_flag OR Error_flag OR Int_temp=0 THEN RETURN 7026 IF Int_temp<0 OR Int_temp>32767 THEN 7028 BEEP 7030 DISP "***** Invalid Block_size parameter *****" 7032 WAIT 3 7034 RETURN 7036 END IF 7038 Block_size=Int_temp 7040 ! 7042 ! Lets get the block from the hardware 7044 ! 7046 ALLOCATE INTEGER Block(0:Block_size-1) 7048 DISP "Getting block ..." 7050 Hw_read_blk((Block_id),Block(*),5) ! get block from HP-IB module 7052 IF FNHw_io_error THEN 7054 BEEP 7056 DISP "***** Unable to read block from hardware *****" 7058 WAIT 3 7060 ELSE 7062 INTEGER Done_blkfs_loop 7064 S_disp_height=S_height-11 7066 Block_offset=0 7068 GOSUB Icode_win_blk 7070 Done_blkfs_loop=0 7072 REPEAT 7074 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 7076 ON KEY 1 LABEL FNUser_keylabel$("Prev Page") CALL User_key1isr 7078 ON KEY 2 LABEL FNUser_keylabel$("Next Page") CALL User_key2isr 7080 ON KEY 3 LABEL FNUser_keylabel$("Prev Line") CALL User_key3isr 7082 ON KEY 4 LABEL FNUser_keylabel$("Next Line") CALL User_key4isr 7084 ON KEY 5 LABEL FNUser_keylabel$("Offset") CALL User_key5isr 7086 ON KEY 6 LABEL FNUser_keylabel$(" ") CALL User_key6isr 7088 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 7090 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 7092 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 7094 REPEAT 7096 GOSUB Icode_state_str 7098 Mode_str$=Ver_str$&" "&State_str$&" BLOCK disp mode." 7100 DISP Mode_str$;" Enter softkey." 7102 UNTIL FNUser_key_press 7104 SELECT FNUser_get_key 7106 CASE 1 7108 Block_offset=Block_offset-(Elmnts_per_line*Elmnt_size*(S_disp_height-5)) 7110 GOSUB Icode_win_blk 7112 CASE 2 7114 Block_offset=Block_offset+(Elmnts_per_line*Elmnt_size*(S_disp_height-5)) 7116 GOSUB Icode_win_blk 7118 CASE 3 7120 Block_offset=Block_offset-(Elmnts_per_line*Elmnt_size) 7122 GOSUB Icode_win_blk 7124 CASE 4 7126 Block_offset=Block_offset+(Elmnts_per_line*Elmnt_size) 7128 GOSUB Icode_win_blk 7130 CASE 5 7132 Icode_inpt_num(Mode_str$&" Enter new offset:",Int_temp,Null_flag,Error_flag) 7134 IF NOT Null_flag AND NOT Error_flag THEN 7136 Block_offset=Int_temp 7138 GOSUB Icode_win_blk 7140 END IF 7142 CASE 6 7144 CASE 7 7146 CASE 8 7148 Done_blkfs_loop=1 7150 END SELECT 7152 UNTIL Done_blkfs_loop 7154 END IF 7156 ! 7158 DEALLOCATE Block(*) 7160 RETURN 7162 ! 7164 Icode_win_blk:! 7166 INTEGER Elmnt_size,Elmnts_per_line 7168 IF Disp_blks_form<>2 THEN 7170 Elmnt_size=1 7172 Elmnts_per_line=8 7174 ELSE 7176 Elmnt_size=4 7178 IF (S_width-7) DIV 20>=4 THEN 7180 Elmnts_per_line=4 7182 ELSE 7184 Elmnts_per_line=2 7186 END IF 7188 END IF 7190 Block_offset=MAX(0,Block_offset) 7192 Block_offset=MIN(SIZE(Block,1)-Elmnt_size,Block_offset) 7194 Block_disp_cnt=SIZE(Block,1)-Block_offset DIV Elmnt_size 7196 Block_disp_cnt=MIN(Block_disp_cnt,S_disp_height*Elmnts_per_line) 7198 User_clr_scr 7200 GOSUB Icode_disp_blk 7202 RETURN 7204 ! 7206 ! Input: Block(*),Block_offset and Block_disp_cnt 7208 ! 7210 ! This routine is used to display the contents of <block> on the CRT. 7212 ! The block is displayed starting at <block_offset>. <Block_disp_cnt> 7214 ! points are written to the CRT. There is no scrolling. Blocks can be 7216 ! be displayed in decimal, hex or floating point formats. 7218 ! 7220 Icode_disp_blk: ! display Block(*) starting at block_disp_strt 7222 Block_disp_ptr=Block_offset 7224 OUTPUT CRT 7226 SELECT Disp_blks_form 7228 CASE 0 ! Decimal 7230 OUTPUT CRT;" >>> Block: '";Block_name$;"' Display type: Decimal <<<<" 7232 OUTPUT CRT USING "#,7A";"|Offst|" 7234 FOR I=0 TO 7 7236 OUTPUT CRT USING "#,4X,1D,2X";I 7238 NEXT I 7240 OUTPUT CRT;"| Ascii" 7242 OUTPUT CRT;"|-----+";RPT$("-------",7);"-------+----------------" 7244 REPEAT 7246 OUTPUT CRT USING "#,1A, 5D,1A ";"|",Block_disp_ptr,"| " 7248 X_disp_count=MIN(Block_disp_cnt,8) 7250 FOR I=0 TO X_disp_count-1 7252 OUTPUT CRT USING "#,6D,1X";Block(Block_disp_ptr+I) 7254 NEXT I 7256 OUTPUT CRT;RPT$(" ",MAX(0,8-X_disp_count)); 7258 OUTPUT CRT;" "; 7260 FOR I=0 TO X_disp_count-1 7262 OUTPUT CRT;FNIcode_asc_str$(Block(Block_disp_ptr+I)); 7264 NEXT I 7266 OUTPUT CRT 7268 Block_disp_ptr=Block_disp_ptr+X_disp_count 7270 Block_disp_cnt=Block_disp_cnt-X_disp_count 7272 UNTIL Block_disp_cnt=0 7274 CASE 1 ! Hex 7276 OUTPUT CRT;" >>> Block: '";Block_name$;"' Display type: Hex <<<<" 7278 OUTPUT CRT USING "#,7A";"|Offst| " 7280 FOR I=0 TO 7 7282 OUTPUT CRT USING "#,2X,1D,3X";I 7284 NEXT I 7286 OUTPUT CRT;"| Ascii" 7288 OUTPUT CRT;"|-----+-";RPT$("------",7);"-----+------------------" 7290 REPEAT 7292 OUTPUT CRT USING "#,2A,4A,2A";"|$",IVAL$(Block_disp_ptr,16),"| " 7294 X_disp_count=MIN(Block_disp_cnt,8) 7296 FOR I=0 TO X_disp_count-1 7298 OUTPUT CRT USING "#,4A,2X";IVAL$(Block(Block_disp_ptr+I),16) 7300 NEXT I 7302 OUTPUT CRT;RPT$(" ",MAX(0,8-X_disp_count)); 7304 OUTPUT CRT;" "; 7306 FOR I=0 TO X_disp_count-1 7308 OUTPUT CRT;FNIcode_asc_str$(Block(Block_disp_ptr+I)); 7310 NEXT I 7312 OUTPUT CRT 7314 Block_disp_ptr=Block_disp_ptr+X_disp_count 7316 Block_disp_cnt=Block_disp_cnt-X_disp_count 7318 UNTIL Block_disp_cnt=0 7320 CASE 2 ! Floating Point 7322 OUTPUT CRT;" >>> Block: '";Block_name$;"' Display type: Floating point <<<<" 7324 OUTPUT CRT USING "#,7A";"|Offst|" 7326 X_disp_count=(S_width-7) DIV 20 7328 IF X_disp_count>=4 THEN 7330 X_disp_count=4 7332 ELSE 7334 X_disp_count=2 7336 END IF 7338 FOR I=0 TO X_disp_count-1 7340 OUTPUT CRT USING "#,9X,2D,9X";I 7342 NEXT I 7344 OUTPUT CRT;"|" 7346 OUTPUT CRT;"|-----+";RPT$("--------------------",X_disp_count);"|" 7348 REPEAT 7350 OUTPUT CRT USING "#,1A, 5D,1A ";"|",Block_disp_ptr,"| " 7352 X_disp_count=MIN(Block_disp_cnt,X_disp_count) 7354 FOR I=0 TO X_disp_count-1 7356 Lib_64_to_float(Block(Block_disp_ptr),Block(Block_disp_ptr+1),Block(Block_disp_ptr+2),Block(Block_disp_ptr+3),Real_temp,Not_a_num_flag) 7358 IF Not_a_num_flag THEN 7360 OUTPUT CRT;" Not a number "; 7362 ELSE 7364 OUTPUT CRT USING "#,MZ.DDDDDDDDDDDESZZZ,1X";Real_temp 7366 END IF 7368 Block_disp_ptr=Block_disp_ptr+4 7370 Block_disp_cnt=Block_disp_cnt-1 7372 NEXT I 7374 OUTPUT CRT 7376 UNTIL Block_disp_cnt=0 7378 END SELECT 7380 RETURN 7382 ! 7384 ! Input: Key_pressed Output: Disp_blks_form 7386 ! 7388 ! This routine is used to change the block display format. 7390 ! 7392 Icode_blks_newf: ! new block display format 7394 SELECT Disp_blks_form 7396 CASE 0 7398 IF Key_pressed=5 THEN Disp_blks_form=1 7400 IF Key_pressed=6 THEN Disp_blks_form=2 7402 CASE 1 7404 IF Key_pressed=5 THEN Disp_blks_form=0 7406 IF Key_pressed=6 THEN Disp_blks_form=2 7408 CASE 2 7410 IF Key_pressed=5 THEN Disp_blks_form=0 7412 IF Key_pressed=6 THEN Disp_blks_form=1 7414 END SELECT 7416 RETURN 7418 ! 7420 ! This routine is used to display the list of block names and their 7422 ! current id's on the CRT. There is no scrolling here either. 7424 ! 7426 Icode_list_blks: ! Blk_disp_strt and Blk_disp_cnt are parameters 7428 IF Blk_disp_cnt<>0 THEN 7430 ! 7432 GOSUB Icode_r_varvals ! read variable table. Need this because some 7434 ! block id's are in variables. 7436 X_disp_count=S_width DIV 24 7438 OUTPUT CRT 7440 OUTPUT CRT;"|"; 7442 FOR I=1 TO X_disp_count 7444 OUTPUT CRT USING "#,16A,1X,5A,1A";"Block name"," Id ","|" 7446 NEXT I 7448 OUTPUT CRT 7450 OUTPUT CRT;"|"; 7452 FOR I=1 TO X_disp_count 7454 OUTPUT CRT USING "#,16A,1A,5A,1A";RPT$("-",16),"+",RPT$("-",5),"|" 7456 NEXT I 7458 OUTPUT CRT 7460 Blk_ptr=Blk_disp_strt 7462 Blk_disp_stop=Blk_ptr+Blk_disp_cnt-1 7464 Count=0 7466 WHILE Blk_ptr<=Blk_disp_stop 7468 IF Count MOD X_disp_count=0 THEN OUTPUT CRT;"|"; 7470 GOSUB Icode_blk_id ! get Block_id from blk_ptr 7472 OUTPUT CRT USING "#,16A,1X,5D,1A";Info$(Blk_ptr)[1,16],Block_id,"|" 7474 Blk_ptr=Blk_ptr+1 7476 Count=Count+1 7478 IF Count MOD X_disp_count=0 THEN OUTPUT CRT 7480 END WHILE 7482 OUTPUT CRT 7484 END IF 7486 RETURN 7488 ! 7490 ! Input: Block_name$ Output: Block_ptr 7492 ! 7494 ! This routine is used to search Info$ for the line that contains 7496 ! the information about <block_name$>. Returned is a pointer into 7498 ! Info$. 7500 ! 7502 Icode_blk_ptr:! 7504 FOR Blk_ptr=Blk_infostrt TO Blk_infolast 7506 IF Block_name$=TRIM$(Info$(Blk_ptr)[1,16]) THEN RETURN 7508 NEXT Blk_ptr 7510 BEEP 7512 DISP "***** Undefined block name - '";Block_name$;"' *****" 7514 WAIT 3 7516 Blk_ptr=-1 7518 RETURN 7520 ! 7522 ! Input: Blk_ptr Output: Block_id 7524 ! 7526 ! This routine is used to get the current block id of the block 7528 ! pointed to by <Blk_ptr>. <Blk_ptr> points into Info$. 7530 ! 7532 Icode_blk_id: ! Returns Block_id from Blk_ptr 7534 SELECT Blk_ptr 7536 CASE <=Blkext_infolast ! ext block 7538 Block_id=VAL(Info$(Blk_ptr)[35,39]) 7540 CASE <=Blkvar_infolast ! var block 7542 GOSUB Icode_r_varvals 7544 Var_num=VAL(Info$(Blk_ptr)[17,21]) 7546 Int_hi=Var_values(Var_num*2) ! this should be 0 7548 Int_lo=Var_values(Var_num*2+1) 7550 Block_id=Int_lo 7552 CASE <=Blkcon_infolast ! con block 7554 Block_id=VAL(Info$(Blk_ptr)[17,21]) 7556 CASE ELSE 7558 BEEP 7560 DISP "***** Illegal block id - '";Block_id;"' *****" 7562 WAIT 3 7564 Block_id=-1 7566 END SELECT 7568 RETURN 7570 ! 7572 ! This routine is used to initialize the block section of the debugger. 7574 ! 7576 Icode_blks_init:! 7578 Disp_blks_form=VAL(Info$(5)[12;1]) 7580 ! 7582 Blk_infostrt=-1 ! points to beginning of the first block table 7584 Blk_infolast=-1 ! points to the end of the last block table 7586 ! 7588 ! Pull out information about DEFBLK_SP/DEFBLK_MAIN/DEFBLK_EXT table 7590 ! from Info$ 7592 ! 7594 Blkext_infostrt=VAL(Info$(1)[1,5]) 7596 Blkext_infocnt=VAL(Info$(1)[6,10]) 7598 Blkext_infolast=Blkext_infostrt+Blkext_infocnt-1 7600 IF Blkext_infocnt<>0 THEN 7602 Blk_infostrt=Blkext_infostrt 7604 Blk_infolast=Blkext_infolast 7606 END IF 7608 ! 7610 ! Pull out information about DEFBLK_VAR table from Info$ 7612 ! 7614 Blkvar_infostrt=VAL(Info$(2)[1,5]) 7616 Blkvar_infocnt=VAL(Info$(2)[6,10]) 7618 Blkvar_infolast=Blkvar_infostrt+Blkvar_infocnt-1 7620 IF Blkvar_infocnt<>0 THEN 7622 IF Blk_infostrt=-1 THEN Blk_infostrt=Blkvar_infostrt 7624 Blk_infolast=Blkvar_infolast 7626 END IF 7628 ! 7630 ! Pull out information about DEFBLK_CON table from Info$ 7632 ! 7634 Blkcon_infostrt=VAL(Info$(3)[1,5]) 7636 Blkcon_infocnt=VAL(Info$(3)[6,10]) 7638 Blkcon_infolast=Blkcon_infostrt+Blkcon_infocnt-1 7640 IF Blkcon_infocnt<>0 THEN 7642 IF Blk_infostrt=-1 THEN Blk_infostrt=Blkcon_infostrt 7644 Blk_infolast=Blkcon_infolast 7646 END IF 7648 RETURN 7650 ! 7652 ! **************************** SOURCE ************************** 7654 ! 7656 ! This routine is used to display source code. Obviously, the 7658 ! source code can not be displayed unless the optional parameter 7660 ! <Source$> was passed into the debugger. Most of the functions 7662 ! of the source section of the debugger can be used to display 7664 ! only a small section of the ICODE program. This may be useful 7666 ! if the user wishes to display two, or more, types of information 7668 ! on the CRT. The functions provided in the source menu are as 7670 ! follows: 7672 ! 1 - Display source. User specifies start line and stop line. 7674 ! 2 - Display source. User specifies start line and count. 7676 ! 3 - Display source. User specifies stop line and count. 7678 ! 4 - Display source. User specifies center line and count. 7680 ! 5 - Display label list. No scrolling. 7682 ! 6 - Enter full screen source display mode. 7684 ! 7 - 7686 ! 8 - Return to main menu. 7688 ! 7690 INTEGER Done_src_loop,Src_present,Src_size 7692 INTEGER Lbl_infostrt,Lbl_infolast,Lbl_infocnt 7694 INTEGER Lbl_disp_ptr,Lbl_disp_strt,Lbl_disp_stop,Lbl_disp_cnt 7696 INTEGER Src_disp_strt,Src_disp_stop,Src_disp_cnt,Src_disp_cent 7698 INTEGER Lbl_ptr,Lbl_obj_addr,Lbl_src_addr 7700 INTEGER Src_addr,Obj_addr,Test_obj_addr,Test_src_addr 7702 INTEGER Info_inst_strt,Info_inst_cnt,Inst_cnt 7704 INTEGER F_pause,C_nop 7706 DIM Label_name$[20] 7708 ! 7710 Icode_src:! 7712 IF Src_present THEN 7714 GOSUB Icode_do_src 7716 ELSE 7718 BEEP 7720 OUTPUT CRT 7722 OUTPUT CRT;"*** Source(*) code not passed to debugger ***" 7724 END IF 7726 RETURN 7728 ! 7730 Icode_do_src:! 7732 Done_src_loop=0 7734 REPEAT 7736 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 7738 ON KEY 1 LABEL FNUser_keylabel$("Line to Line") CALL User_key1isr 7740 ON KEY 2 LABEL FNUser_keylabel$("After Line") CALL User_key2isr 7742 ON KEY 3 LABEL FNUser_keylabel$("Before Line") CALL User_key3isr 7744 ON KEY 4 LABEL FNUser_keylabel$("About Line") CALL User_key4isr 7746 ON KEY 5 LABEL FNUser_keylabel$("List Labels") CALL User_key5isr 7748 ON KEY 6 LABEL FNUser_keylabel$("Full Screen") CALL User_key6isr 7750 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 7752 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 7754 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 7756 REPEAT 7758 GOSUB Icode_state_str 7760 Mode_str$=Ver_str$&" "&State_str$&" SCREEN disp mode." 7762 DISP Mode_str$;" Enter softkey." 7764 UNTIL FNUser_key_press 7766 SELECT FNUser_get_key 7768 CASE 1 ! point to point 7770 GOSUB Icode_src_ltol 7772 CASE 2 ! after line 7774 GOSUB Icode_src_aftr 7776 CASE 3 ! before line 7778 GOSUB Icode_src_bef 7780 CASE 4 ! about line 7782 GOSUB Icode_src_abt 7784 CASE 5 ! List line 7786 Lbl_disp_strt=Lbl_infostrt 7788 Lbl_disp_stop=Lbl_disp_strt+Lbl_infocnt-1 7790 GOSUB Icode_disp_lbls 7792 CASE 6 7794 GOSUB Icode_src_fs 7796 CASE 7 7798 CASE 8 7800 Done_src_loop=1 7802 END SELECT 7804 UNTIL Done_src_loop 7806 RETURN 7808 ! 7810 ! This routine is used to handle full screen source display mode. 7812 ! From here the user can scroll through their source code. 7814 ! 7816 Icode_src_fs:! 7818 INTEGER Done_fs_loop,Fs_disp_strt 7820 S_disp_height=S_height-9 7822 GOSUB Icode_disp_fs 7824 Done_fs_loop=0 7826 REPEAT 7828 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 7830 ON KEY 1 LABEL FNUser_keylabel$("Prev Page") CALL User_key1isr 7832 ON KEY 2 LABEL FNUser_keylabel$("Next Page") CALL User_key2isr 7834 ON KEY 3 LABEL FNUser_keylabel$("Prev Line") CALL User_key3isr 7836 ON KEY 4 LABEL FNUser_keylabel$("Next Line") CALL User_key4isr 7838 ON KEY 5 LABEL FNUser_keylabel$("Begin") CALL User_key5isr 7840 ON KEY 6 LABEL FNUser_keylabel$("End") CALL User_key6isr 7842 ON KEY 7 LABEL FNUser_keylabel$("") CALL User_key7isr 7844 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 7846 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 7848 REPEAT 7850 GOSUB Icode_state_str 7852 Mode_str$=Ver_str$&" "&State_str$&" SOURCE disp mode." 7854 DISP Mode_str$;" Enter softkey." 7856 UNTIL FNUser_key_press 7858 SELECT FNUser_get_key 7860 CASE 1 7862 Src_disp_strt=Src_disp_strt-(S_disp_height-5) 7864 GOSUB Icode_disp_fs 7866 CASE 2 7868 Src_disp_strt=Src_disp_strt+(S_disp_height-5) 7870 GOSUB Icode_disp_fs 7872 CASE 3 7874 Src_disp_strt=Src_disp_strt-1 7876 GOSUB Icode_disp_fs 7878 CASE 4 7880 Src_disp_strt=Src_disp_strt+1 7882 GOSUB Icode_disp_fs 7884 CASE 5 7886 Src_disp_strt=0 7888 GOSUB Icode_disp_fs 7890 CASE 6 7892 Src_disp_strt=32767 7894 GOSUB Icode_disp_fs 7896 CASE 7 7898 CASE 8 7900 Done_fs_loop=1 7902 END SELECT 7904 UNTIL Done_fs_loop 7906 RETURN 7908 ! 7910 ! Input: Src_disp_strt 7912 ! 7914 ! This routine is used to display a screen of source code on the CRT. 7916 ! Given <src_disp_strt> this routine will map <src_disp_strt> and 7918 ! <src_disp_stop> into valid ranges. Also, making sure to use as 7920 ! much of the CRT as possible. Then the source display routine is 7922 ! called. 7924 ! 7926 Icode_disp_fs:! 7928 Src_disp_strt=MAX(0,Src_disp_strt) 7930 Src_disp_strt=MIN(Src_size-1,Src_disp_strt) 7932 Src_disp_stop=MIN(Src_size-1,(Src_disp_strt+0.)+S_disp_height-1) 7934 IF Src_disp_stop=Src_size-1 THEN Src_disp_strt=MAX(0,Src_disp_stop-S_disp_height+1) 7936 User_clr_scr 7938 GOSUB Icode_disp_src 7940 RETURN 7942 ! 7944 ! This routine is used to display source code with the user specifying 7946 ! a start line and a stop line. 7948 ! 7950 Icode_src_ltol:! 7952 Icode_inpt_num(Mode_str$&" Enter start disp line:",Src_disp_strt,Null_flag,Error_flag,Label_name$) 7954 IF Label_name$<>"" THEN 7956 GOSUB Icode_lbl_srca ! returns Lbl_src_addr from Label_name$ 7958 IF Label_name$="STOP" OR Label_name$="END" THEN 7960 GOSUB Icode_src_lerr 7962 Src_disp_strt=-1 7964 ELSE 7966 Src_disp_strt=Lbl_src_addr 7968 END IF 7970 ELSE 7972 IF Null_flag OR Error_flag THEN 7974 Src_disp_strt=-1 7976 ELSE 7978 IF Src_disp_strt<0 OR Src_disp_strt>Src_size-1 THEN 7980 GOSUB Icode_src_lerr 7982 Src_disp_strt=-1 7984 END IF 7986 END IF 7988 END IF 7990 IF Src_disp_strt<>-1 THEN 7992 Icode_inpt_num(Mode_str$&" Enter stop disp line:",Src_disp_stop,Null_flag,Error_flag,Label_name$) 7994 IF Label_name$<>"" THEN 7996 GOSUB Icode_lbl_srca ! returns Lbl_src_addr from Label_name$ 7998 IF Label_name$="START" OR Label_name$="BEGIN" THEN 8000 GOSUB Icode_src_lerr 8002 Src_disp_stop=-1 8004 ELSE 8006 Src_disp_stop=Lbl_src_addr 8008 END IF 8010 ELSE 8012 IF Null_flag OR Error_flag THEN Src_disp_stop=-1 8014 END IF 8016 IF Src_disp_stop<>-1 THEN 8018 GOSUB Icode_disp_src 8020 END IF 8022 END IF 8024 RETURN 8026 ! 8028 ! This routine is used to display source code with the user specifying 8030 ! a start line and a count. 8032 ! 8034 Icode_src_aftr:! 8036 Icode_inpt_num(Mode_str$&" Enter start disp line:",Src_disp_strt,Null_flag,Error_flag,Label_name$) 8038 IF Label_name$<>"" THEN 8040 GOSUB Icode_lbl_srca ! returns Lbl_src_addr from Label_name$ 8042 IF Label_name$="STOP" OR Label_name$="END" THEN 8044 GOSUB Icode_src_lerr 8046 Src_disp_strt=-1 8048 ELSE 8050 Src_disp_strt=Lbl_src_addr 8052 IF Src_disp_strt<0 OR Src_disp_strt>Src_size-1 THEN 8054 GOSUB Icode_src_lerr 8056 Src_disp_strt=-1 8058 END IF 8060 END IF 8062 ELSE 8064 IF Null_flag OR Error_flag THEN 8066 Src_disp_strt=-1 8068 ELSE 8070 IF Src_disp_strt<0 OR Src_disp_stop>Src_size-1 THEN 8072 GOSUB Icode_src_lerr 8074 Src_disp_strt=-1 8076 END IF 8078 END IF 8080 END IF 8082 IF Src_disp_strt>=0 THEN 8084 Icode_inpt_num(Mode_str$&" Enter # of disp lines:",Src_disp_cnt,Null_flag,Error_flag) 8086 IF NOT Null_flag AND NOT Error_flag THEN 8088 Src_disp_stop=Src_disp_strt+Src_disp_cnt-1 8090 GOSUB Icode_disp_src 8092 END IF 8094 END IF 8096 RETURN 8098 ! 8100 ! This routine is used to display source code with the user specifying 8102 ! the last line and a count. 8104 ! 8106 Icode_src_bef:! 8108 Icode_inpt_num(Mode_str$&" Enter last disp line:",Src_disp_stop,Null_flag,Error_flag,Label_name$) 8110 IF Label_name$<>"" THEN 8112 GOSUB Icode_lbl_srca ! returns Lbl_src_addr from Label_name$ 8114 IF Label_name$="BEGIN" OR Label_name$="START" THEN 8116 GOSUB Icode_src_lerr 8118 Src_disp_stop=-1 8120 ELSE 8122 Src_disp_stop=Lbl_src_addr 8124 IF Src_disp_stop<0 OR Src_disp_stop>Src_size-1 THEN 8126 GOSUB Icode_src_lerr 8128 Src_disp_strt=-1 8130 END IF 8132 END IF 8134 ELSE 8136 IF Null_flag OR Error_flag THEN 8138 Src_disp_stop=-1 8140 ELSE 8142 IF Src_disp_stop<0 OR Src_disp_stop>Src_size-1 THEN 8144 GOSUB Icode_src_lerr 8146 Src_disp_stop=-1 8148 END IF 8150 END IF 8152 END IF 8154 IF Src_disp_stop<>-1 THEN 8156 Icode_inpt_num(Mode_str$&" Enter # of disp lines:",Src_disp_cnt,Null_flag,Error_flag) 8158 IF NOT Null_flag AND NOT Error_flag THEN 8160 Src_disp_strt=Src_disp_stop-Src_disp_cnt+1 8162 GOSUB Icode_disp_src 8164 END IF 8166 END IF 8168 RETURN 8170 ! 8172 ! This routine is used to display source code with the user specifying 8174 ! a center line and a count. 8176 ! 8178 Icode_src_abt:! 8180 Icode_inpt_num(Mode_str$&" Enter center disp line:",Src_disp_cent,Null_flag,Error_flag,Label_name$) 8182 IF Label_name$<>"" THEN 8184 GOSUB Icode_lbl_srca ! returns Lbl_src_addr from Label_name$ 8186 IF Label_name$="BEGIN" OR Label_name$="START" THEN 8188 GOSUB Icode_src_lerr 8190 Src_disp_cent=-1 8192 ELSE 8194 Src_disp_cent=Lbl_src_addr 8196 END IF 8198 ELSE 8200 IF Null_flag OR Error_flag THEN 8202 Src_disp_cent=-1 8204 END IF 8206 END IF 8208 IF Src_disp_cent<>-1 THEN 8210 Icode_inpt_num(Mode_str$&" Enter # of disp lines:",Src_disp_cnt,Null_flag,Error_flag) 8212 IF NOT Null_flag AND NOT Error_flag THEN 8214 Src_disp_strt=Src_disp_cent-Src_disp_cnt DIV 2 8216 Src_disp_stop=Src_disp_cent+Src_disp_cnt DIV 2 8218 GOSUB Icode_disp_src 8220 END IF 8222 END IF 8224 RETURN 8226 ! 8228 ! Input: Lbl_disp_strt and Lbl_disp_stop 8230 ! 8232 ! This routine is used to display a section of the label table. 8234 ! Currently, only the entire label table is displayed. 8236 ! 8238 Icode_disp_lbls:! 8240 OUTPUT CRT 8242 Lbl_disp_cnt=Lbl_disp_stop-Lbl_disp_strt+1 8244 OUTPUT CRT;">>>> Label Listing. ";Lbl_disp_cnt;" label(s) present. <<<<" 8246 IF Lbl_disp_cnt>0 THEN 8248 X_disp_count=MIN(S_width DIV 25,Lbl_disp_cnt) 8250 OUTPUT CRT;"|"; 8252 FOR I=1 TO X_disp_count 8254 OUTPUT CRT USING "#,16A,1X,5A,1A";"Label Name","Offst","|" 8256 NEXT I 8258 OUTPUT CRT 8260 OUTPUT CRT;"|"; 8262 FOR I=1 TO X_disp_count 8264 OUTPUT CRT USING "#,16A,1A,5A,1A";RPT$("-",16),"+",RPT$("-",5),"|" 8266 NEXT I 8268 OUTPUT CRT 8270 Lbl_disp_ptr=Lbl_disp_strt 8272 Disp_cnt=0 8274 REPEAT 8276 IF Disp_cnt MOD X_disp_count=0 THEN OUTPUT CRT;"|"; 8278 OUTPUT CRT USING "#,16A,1X,1A,4A,1A";Info$(Lbl_disp_ptr)[1,16],"$",IVAL$(VAL(Info$(Lbl_disp_ptr)[17,21]),16),"|" 8280 Disp_cnt=Disp_cnt+1 8282 IF Disp_cnt MOD X_disp_count=0 THEN OUTPUT CRT 8284 Lbl_disp_ptr=Lbl_disp_ptr+1 8286 UNTIL Lbl_disp_ptr>Lbl_disp_stop 8288 IF Disp_cnt MOD X_disp_count<>0 THEN OUTPUT CRT 8290 END IF 8292 RETURN 8294 ! 8296 ! Input: Src_disp_strt and Src_disp_stop 8298 ! 8300 ! This routine is used to display a section of the source code to the 8302 ! CRT. 8304 ! 8306 Icode_disp_src: ! Src_disp_strt and Src_disp_stop are parameters 8308 Src_disp_strt=MAX(0,Src_disp_strt) 8310 Src_disp_stop=MIN(Src_size-1,Src_disp_stop) 8312 OUTPUT CRT 8314 OUTPUT CRT;">>>> Source Listing. Lines ";Src_disp_strt;" through ";Src_disp_stop;". <<<<" 8316 FOR I=Src_disp_strt TO Src_disp_stop 8318 OUTPUT CRT USING "5D,1X,K";I,Source$(I) 8320 NEXT I 8322 RETURN 8324 ! 8326 ! Input: Label_name$ Output: Lbl_src_addr 8328 ! 8330 ! This routine is used to translate a label name into the corresponding 8332 ! source code address. 8334 ! 8336 Icode_lbl_srca:! 8338 GOSUB Icode_lbl_ptr 8340 Lbl_src_addr=-1 8342 IF Lbl_ptr=-1 THEN 8344 IF Label_name$="BEGIN" OR Label_name$="START" THEN Lbl_src_addr=0 8346 IF Label_name$="END" OR Label_name$="STOP" THEN Lbl_src_addr=Src_size-1 8348 IF Lbl_src_addr=-1 THEN 8350 BEEP 8352 DISP "***** Undefined label reference - '";Label_name$;"' *****" 8354 WAIT 3 8356 END IF 8358 ELSE 8360 Lbl_src_addr=VAL(Info$(Lbl_ptr)[22,26]) 8362 END IF 8364 RETURN 8366 ! 8368 ! Input: Label_name$ Output: Lbl_obj_addr 8370 ! 8372 ! This routine is used to translate a label_name into the corresponding 8374 ! object code address. 8376 ! 8378 Icode_lbl_obja:! 8380 GOSUB Icode_lbl_ptr 8382 IF Lbl_ptr=-1 THEN 8384 IF Label_name$="BEGIN" OR Label_name$="START" THEN Lbl_obj_addr=0 8386 IF Label_name$="END" OR Label_name$="STOP" THEN Lbl_obj_addr=Obj_size-1 8388 Lbl_obj_addr=-1 8390 ELSE 8392 Lbl_obj_addr=VAL(Info$(Lbl_ptr)[17,21]) 8394 END IF 8396 RETURN 8398 ! 8400 ! Input: Label_name$ Output: Lbl_ptr 8402 ! 8404 ! This routine is used to translate a label name into a pointer into 8406 ! Info$ for the corresponding label. 8408 ! 8410 Icode_lbl_ptr: ! Returns Lbl_ptr from Label_name$ 8412 IF Lbl_infocnt<>0 THEN 8414 FOR Lbl_ptr=Lbl_infostrt TO Lbl_infolast 8416 IF Label_name$=TRIM$(Info$(Lbl_ptr)[1,16]) THEN RETURN 8418 NEXT Lbl_ptr 8420 END IF 8422 Lbl_ptr=-1 8424 RETURN 8426 ! 8428 ! No comment 8430 ! 8432 Icode_src_lerr:! 8434 BEEP 8436 DISP "***** Invalid Source$(*) line parameter *****" 8438 WAIT 3 8440 RETURN 8442 ! 8444 ! Input: Src_addr Output: Obj_addr 8446 ! 8448 ! This routine is used to translate an object address into the 8450 ! corresponding source code address. 8452 ! 8454 Icode_src_2_obj:! 8456 Info_ptr=Info_inst_strt 8458 FOR Inst_ptr=0 TO Inst_cnt-1 8460 IF Inst_ptr MOD 10=0 THEN 8462 Temp$=Info$(Info_ptr) 8464 Info_ptr=Info_ptr+1 8466 END IF 8468 ENTER Temp$ USING "#,W,W";Obj_addr,Test_src_addr 8470 IF Test_src_addr=Src_addr THEN RETURN 8472 Temp$=Temp$[5] 8474 NEXT Inst_ptr 8476 Obj_addr=-1 8478 RETURN 8480 ! 8482 ! Input: Src_addr Output: Obj_addr 8484 ! 8486 ! This routine is used to translate a source code address into an 8488 ! object code address. 8490 ! 8492 Icode_obj_2_src:! 8494 Info_ptr=Info_inst_strt 8496 FOR Inst_ptr=0 TO Inst_cnt-1 8498 IF Inst_ptr MOD 10=0 THEN 8500 Temp$=Info$(Info_ptr) 8502 Info_ptr=Info_ptr+1 8504 END IF 8506 ENTER Temp$ USING "#,W,W";Test_obj_addr,Src_addr 8508 IF Test_obj_addr=Obj_addr THEN RETURN 8510 Temp$=Temp$[5] 8512 NEXT Inst_ptr 8514 Src_addr=-1 8516 RETURN 8518 ! 8520 ! This routine is used to initialize the source code section of the 8522 ! debugger. 8524 ! 8526 Icode_src_init:! 8528 Fs_disp_ptr=-1 8530 ! 8532 Lbl_infostrt=VAL(Info$(5)[1,5]) 8534 Lbl_infocnt=VAL(Info$(5)[6,10]) 8536 Lbl_infolast=Lbl_infostrt+Lbl_infocnt-1 8538 ! 8540 ! Get pointers into Info$ where the instruction table is. The 8542 ! instruction table has an entry for each instruction. Each entry 8544 ! has info about source code address and object code address. 8546 ! 8548 Info_inst_strt=VAL(Info$(2)[11,15]) ! get source code info 8550 Inst_cnt=VAL(Info$(2)[16,20]) ! from Info$ 8552 Info_inst_cnt=Inst_cnt DIV 10 8554 ! 8556 Src_size=VAL(Info$(1)[16,20]) 8558 ! 8560 Src_present=0 8562 IF NPAR=3 THEN 8564 Src_present=1 8566 IF SIZE(Source$,1)<>Src_size THEN 8568 Error_string$="Info$(*) format error. Invaid SIZE(Source$(*))." 8570 GOSUB Icode_dbg_err 8572 END IF 8574 END IF 8576 RETURN 8578 ! 8580 ! *********************** HISTORY ***************************** 8582 ! 8584 ! This section of the debugger will display the ICODE history on 8586 ! the CRT. 8588 ! 8590 INTEGER Hist_fifo_ptr,Hist_fifo_wrap,Info_hist_strt,Hist_str_ptr 8592 INTEGER Hist_addr(0:19),Hist_opcode(0:19) 8594 INTEGER Hist_disp_ptr,Hist_disp_cnt 8596 ! 8598 Icode_hist: ! 8600 GOSUB Icode_updt_hist ! update history 8602 GOSUB Icode_disp_hist ! display history 8604 RETURN 8606 ! 8608 Icode_rst_hist: ! initialize history queue to null 8610 Hist_fifo_ptr=-1 8612 Hist_fifo_wrap=0 8614 RETURN 8616 ! 8618 ! This subroutine is used to retrieve a stored history queue form the 8620 ! Info$(*) array. 8622 ! 8624 Icode_get_ihist:! 8626 Info_hist_strt=VAL(Info$(3)[11,15]) 8628 ! 8630 Hist_fifo_ptr=VAL(Info$(Info_hist_strt)[1,5]) 8632 Hist_fifo_wrap=VAL(Info$(Info_hist_strt)[6,10]) 8634 Temp$=Info$(Info_hist_strt+1) 8636 FOR I=0 TO 19 8638 ENTER Temp$ USING "#,W";Hist_addr(I) 8640 Temp$=Temp$[3] 8642 NEXT I 8644 Temp$=Info$(Info_hist_strt+2) 8646 FOR I=0 TO 19 8648 ENTER Temp$ USING "#,W";Hist_opcode(I) 8650 Temp$=Temp$[3] 8652 NEXT I 8654 RETURN 8656 ! 8658 ! This subroutine is used to put the debugger's internal ICODE history 8660 ! queue in Info$. This enables the user to exit the debugger, then 8662 ! re-enter the debugger and still have an accurate history queue. 8664 ! 8666 Icode_put_ihist: ! put history queue in Info$(*) 8668 Info$(Info_hist_strt)[1,5]=VAL$(Hist_fifo_ptr) 8670 Info$(Info_hist_strt)[6,10]=VAL$(Hist_fifo_wrap) 8672 Info$(Info_hist_strt+1)="" 8674 FOR I=0 TO 19 8676 OUTPUT Temp$ USING "#,W";Hist_addr(I) 8678 Info$(Info_hist_strt+1)=Info$(Info_hist_strt+1)&Temp$ 8680 NEXT I 8682 Info$(Info_hist_strt+2)="" 8684 FOR I=0 TO 19 8686 OUTPUT Temp$ USING "#,W";Hist_opcode(I) 8688 Info$(Info_hist_strt+2)=Info$(Info_hist_strt+2)&Temp$ 8690 NEXT I 8692 RETURN 8694 ! 8696 ! This subroutine is used to update the history queue internal to 8698 ! the debugger from the HP-IB module using the IHQ? command. 8700 ! 8702 Icode_updt_hist:! 8704 Temp$=TRIM$(FNHw_cmd_rsp$("ihq?",3)) 8706 GOSUB Icode_hw_err_ck 8708 WHILE Temp$<>"" 8710 Hist_fifo_ptr=Hist_fifo_ptr+1 8712 IF Hist_fifo_ptr=20 THEN 8714 Hist_fifo_ptr=0 8716 Hist_fifo_wrap=1 8718 END IF 8720 Hist_addr(Hist_fifo_ptr)=VAL(Temp$) 8722 Temp$=Temp$[POS(Temp$,",")+1] 8724 Hist_opcode(Hist_fifo_ptr)=VAL(Temp$) 8726 Hist_str_ptr=POS(Temp$,",") 8728 IF Hist_str_ptr=0 THEN Hist_str_ptr=LEN(Temp$) 8730 Temp$=Temp$[Hist_str_ptr+1] 8732 END WHILE 8734 RETURN 8736 ! 8738 ! This subroutine is used to display the history queue. 8740 ! 8742 Icode_disp_hist: ! disp history queue 8744 IF Hist_fifo_ptr=-1 THEN 8746 OUTPUT CRT 8748 OUTPUT CRT;">>>> NO history <<<<" 8750 ELSE 8752 IF Hist_fifo_wrap THEN 8754 Hist_disp_ptr=Hist_fifo_ptr+1 8755 IF Hist_disp_ptr=20 THEN Hist_disp_ptr=0 8757 Hist_disp_cnt=20 8758 ELSE 8760 Hist_disp_ptr=0 8762 Hist_disp_cnt=Hist_fifo_ptr+1 8764 END IF 8766 IF 0 THEN 8768 Int_temp=Hist_disp_cnt-S_height-9 8770 IF Int_temp>0 THEN 8772 Hist_disp_ptr=(Hist_disp_ptr+Int_temp) MOD 20 8774 Hist_disp_cnt=Hist_disp_cnt-Int_temp 8776 END IF 8778 END IF 8780 OUTPUT CRT 8782 OUTPUT CRT USING "1A,4A,1A,5A,1A,K";"|"," OBJ","|"," SRCE","|"," SOURCE LINE" 8784 OUTPUT CRT USING "5A,1A,5A,1A,68A";"-----","+","-----","+",RPT$("-",68) 8786 REPEAT 8788 Obj_addr=Hist_addr(Hist_disp_ptr) 8790 IF Obj_addr=0 THEN ! Is it the assembler inserted c_goto 8792 ! around the variable table? 8794 OUTPUT CRT USING "1A,4A,1X,5X,1X,K";"$",IVAL$(Hist_addr(Hist_disp_ptr),16),RPT$(" ",15)&"<c_goto>" 8796 ELSE 8798 GOSUB Icode_obj_2_src ! returns Src_addr from Obj_addr 8800 IF Src_addr>0 THEN ! Is it assembler inserted inst 8802 ! used for break points? 8804 ! Must be a regular old instruction 8806 IF Src_present THEN 8808 OUTPUT CRT USING "1A,4A,1X,5D,1X,K";"$",IVAL$(Hist_addr(Hist_disp_ptr),16),Src_addr,Source$(Src_addr) 8810 ELSE 8812 OUTPUT CRT USING "1A,4A,1X,5X,1X,6D";"$",IVAL$(Hist_addr(Hist_disp_ptr),16),Hist_opcode(Hist_disp_ptr) 8814 END IF 8816 END IF 8818 END IF 8820 Hist_disp_ptr=Hist_disp_ptr+1 8822 IF Hist_disp_ptr=20 THEN Hist_disp_ptr=0 8824 Hist_disp_cnt=Hist_disp_cnt-1 8826 UNTIL Hist_disp_cnt=0 8828 END IF 8830 RETURN 8832 IF Inst_cnt MOD 10<>0 THEN Info_inst_cnt=Info_inst_cnt+1 8834 RETURN 8836 ! 8838 Icode_hist_init: ! this routine initializes the history debugger code. 8840 GOSUB Icode_get_ihist 8842 RETURN 8844 ! 8846 ! ****************************** TRACE ***************************** 8848 ! 8850 ! This section of code handles the ICODE program control. 8852 ! 8854 ! ****************************************************************** 8856 ! 8858 INTEGER Trace_loop_done,Bkpt_new_addr,Bkpt_obj_addr 8860 INTEGER Cng_from,Cng_to 8862 ! 8864 Icode_trc:! 8866 Trace_loop_done=0 8868 REPEAT 8870 ON KEY 0 LABEL "" GOSUB Icode_dbg_dmy 8872 ON KEY 1 LABEL FNUser_keylabel$("Single Step") CALL User_key1isr 8874 ON KEY 2 LABEL FNUser_keylabel$("Set Break Pt") CALL User_key2isr 8876 ON KEY 3 LABEL FNUser_keylabel$("Clr Break Pt") CALL User_key3isr 8878 ON KEY 4 LABEL FNUser_keylabel$("History") CALL User_key4isr 8880 ON KEY 5 LABEL FNUser_keylabel$("Cont") CALL User_key5isr 8882 ON KEY 6 LABEL FNUser_keylabel$("Pause") CALL User_key6isr 8884 ON KEY 7 LABEL FNUser_keylabel$("Restart") CALL User_key7isr 8886 ON KEY 8 LABEL FNUser_keylabel$("Return") CALL User_key8isr 8888 ON KEY 9 LABEL "" GOSUB Icode_dbg_dmy 8890 REPEAT 8892 GOSUB Icode_state_str ! Get State_str$ 8894 Mode_str$=Ver_str$&" "&State_str$&" TRACE menu." 8896 DISP Mode_str$&" Enter softkey." 8898 UNTIL FNUser_key_press 8900 SELECT FNUser_get_key 8902 CASE 1 8904 GOSUB Icode_sngl_step 8906 CASE 2 8908 GOSUB Icode_set_ubkpt ! set user break point 8910 CASE 3 8912 GOSUB Icode_clr_bkpt 8914 CASE 4 8916 GOSUB Icode_hist 8918 CASE 5 8920 GOSUB Icode_cont 8922 CASE 6 8924 GOSUB Icode_pause 8926 CASE 7 8928 GOSUB Icode_rst_hist 8930 Hw_dev_clear(5) 8932 GOSUB Icode_hw_err_ck 8934 Hw_cmd("abrt;prog "&VAL$(Prog_id),5) 8936 GOSUB Icode_hw_err_ck 8938 OUTPUT CRT 8940 OUTPUT CRT;"ICODE program reset and restarted" 8942 CASE 8 8944 Trace_loop_done=1 8946 END SELECT 8948 UNTIL Trace_loop_done 8950 DISP 8952 RETURN 8954 ! 8956 ! This subroutine is used to continue a PAUSed ICODE program. If the 8958 ! ICODE program is not paused, then an error is generated. 8960 ! 8962 ! NOTE: There is a chance that the ICODE program could be continued 8964 ! in between the time the program state is checked and the time 8966 ! the CONT command is sent. If this happens, then the HP-IB 8968 ! module will generate an error. This will abort the ICODE 8970 ! program. Oops!!!!!!!!!!!!!!! 8972 ! 8974 Icode_cont: ! continue ICODE program 8976 GOSUB Icode_state ! returns Icode_active and Icode_paused 8978 IF Icode_paused THEN 8980 Hw_cmd("cont",3) 8982 GOSUB Icode_hw_err_ck 8984 ELSE 8986 BEEP 8988 DISP "ICODE program not paused" 8990 WAIT 3 8992 END IF 8994 RETURN 8996 ! 8998 ! This subroutine is used to PAUS a running program. If the ICODE 9000 ! program is already paused or not running then an error is generated. 9002 ! 9004 ! NOTE: There is a chance that the ICODE program may pause in between 9006 ! the time its state is checked and the time the PAUS is sent to 9008 ! the HP-IB module. If this happens, an HP-IB module error will 9010 ! be generated. This will also abort the ICODE program. Oops!!!! 9012 ! 9014 Icode_pause:! 9016 GOSUB Icode_state ! returns Icode_paused 9018 IF Icode_paused OR Icode_inactive THEN 9020 BEEP 9022 DISP "ICODE program not running" 9024 WAIT 3 9026 ELSE 9028 Hw_cmd("paus",3) 9030 GOSUB Icode_hw_err_ck 9032 END IF 9034 RETURN 9036 ! 9038 ! This subroutine is used to single step one ICODE instruction. 9040 ! This is done by changing all c_nop's into f_pauses. Sending out 9042 ! a CONT, and then changing all f_pause's, back into c_nop's. Note 9044 ! that this will clear a break point if one is set. 9046 ! 9048 Icode_sngl_step:! 9050 GOSUB Icode_clr_bkpt 9052 GOSUB Icode_state ! returns Icode_inactive and Icode_paused 9054 IF NOT Icode_inactive AND NOT Icode_paused THEN 9056 BEEP 9058 DISP "ICODE program not paused" 9060 WAIT 3 9062 ELSE 9064 DISP "Doing Single Step ..." 9066 Cng_from=C_nop 9068 Cng_to=F_pause 9070 GOSUB Icode_cng_all 9072 IF Icode_inactive THEN 9074 GOSUB Icode_rst_hist 9076 Hw_cmd("prog "&VAL$(Prog_id),3) 9078 ELSE 9080 Hw_cmd("cont",3) 9082 END IF 9084 GOSUB Icode_hw_err_ck 9086 Cng_from=F_pause 9088 Cng_to=C_nop 9090 REPEAT 9092 GOSUB Icode_state ! returns Icode_inactive and Icode_paused 9094 UNTIL Icode_paused OR Icode_inactive 9096 GOSUB Icode_cng_all 9098 END IF 9100 RETURN 9102 ! 9104 ! Input: Cng_from,Cng_to 9106 ! 9108 ! This subroutine is used to change all assembler inserted c_nop's into 9110 ! f_pause's or change all debugger f_pauses' back into c_nop's. 9112 ! 9114 Icode_cng_all:! 9116 ALLOCATE INTEGER Object(0:Obj_size-1) 9118 Hw_read_blk((Prog_id),Object(*),3) 9120 GOSUB Icode_hw_err_ck 9122 Info_ptr=Info_inst_strt 9124 FOR Inst_ptr=0 TO Inst_cnt-1 9126 IF Inst_ptr MOD 10=0 THEN 9128 Temp$=Info$(Info_ptr) 9130 Info_ptr=Info_ptr+1 9132 END IF 9134 ENTER Temp$ USING "#,W,W";Obj_addr,Int_temp 9136 IF Object(Obj_addr-1)=Cng_from THEN 9138 Object(Obj_addr-1)=Cng_to 9140 END IF 9142 Temp$=Temp$[5] 9144 NEXT Inst_ptr 9146 Hw_write_blk((Prog_id),Object(*),3) 9148 GOSUB Icode_hw_err_ck 9150 DEALLOCATE Object(*) 9152 RETURN 9154 ! 9156 ! Input: Bkpt_new_addr 9158 ! 9160 ! This routine is used to set a break point. First a previously set 9162 ! break point is cleared. Then, the ICODE program is checked to make 9164 ! sure that there is a c_nop where the break point is to be set. If 9166 ! not, than an error is generated. Else, the break point is set. 9168 ! 9170 Icode_set_bkpt:! 9172 GOSUB Icode_clr_bkpt 9174 ALLOCATE INTEGER Object(0:Bkpt_new_addr) 9176 Hw_read_blk((Prog_id),Object(*),3) 9178 GOSUB Icode_hw_err_ck 9180 IF Object(Bkpt_new_addr)<>C_nop THEN 9182 BEEP 9184 OUTPUT CRT 9186 OUTPUT CRT;"Can NOT set break point" 9188 DISP "Couldn't find c_nop to overwrite with break point" 9190 WAIT 3 9192 ELSE 9194 Object(Bkpt_new_addr)=F_pause ! Overwrite assembler inserted c_nop 9196 Bkpt_obj_addr=Bkpt_new_addr 9198 Hw_write_blk((Prog_id),Object(*),3) 9200 GOSUB Icode_hw_err_ck 9202 END IF 9204 DEALLOCATE Object(*) 9206 RETURN 9208 Icode_clr_bkpt: ! Clears current break point 9210 IF Bkpt_obj_addr<>-1 THEN 9212 ALLOCATE INTEGER Object(0:Bkpt_obj_addr) 9214 Hw_read_blk((Prog_id),Object(*),3) 9216 GOSUB Icode_hw_err_ck 9218 IF Object(Bkpt_obj_addr)=F_pause THEN 9220 Object(Bkpt_obj_addr)=C_nop 9222 Bkpt_obj_addr=-1 9224 Hw_write_blk((Prog_id),Object(*),3) 9226 GOSUB Icode_hw_err_ck 9228 OUTPUT CRT 9230 OUTPUT CRT;"Break point cleared" 9232 END IF 9234 DEALLOCATE Object(*) 9236 END IF 9238 RETURN 9240 ! 9242 ! This subroutine is used to prompt the user for a break point spot 9244 ! and then set the break point. The break point may be specified by 9246 ! a label name or a source code line number. 9248 ! 9250 Icode_set_ubkpt: ! set user break point 9252 Icode_inpt_num(Mode_str$&" Enter break point line:",Src_addr,Null_flag,Error_flag,Label_name$) 9254 IF Label_name$="" THEN 9256 IF Null_flag OR Error_flag THEN 9258 OUTPUT CRT 9260 OUTPUT CRT;"NO break point set" 9262 ELSE 9264 GOSUB Icode_src_2_obj ! returns obj_addr from src_addr 9266 Bkpt_new_addr=Obj_addr-1 9268 IF Bkpt_new_addr<0 OR Bkpt_new_addr>Obj_size THEN 9270 BEEP 9272 DISP "***** Invalid break point entry *****" 9274 WAIT 3 9276 OUTPUT CRT 9278 OUTPUT CRT;"NO break point set" 9280 ELSE 9282 GOSUB Icode_set_bkpt 9284 END IF 9286 END IF 9288 ELSE 9290 GOSUB Icode_lbl_obja ! returns Lbl_obj_addr from Label_name$ 9292 IF Lbl_obj_addr<>-1 THEN 9294 Bkpt_new_addr=Lbl_obj_addr 9296 GOSUB Icode_set_bkpt 9298 ELSE 9300 BEEP 9302 DISP "***** Invalid label name entry *****" 9304 WAIT 3 9306 OUTPUT CRT 9308 OUTPUT CRT;"NO break point set" 9310 END IF 9312 END IF 9314 RETURN 9316 ! 9318 Icode_get_ibkpt:! ! get break point info from Info$(*) 9320 Bkpt_obj_addr=VAL(Info$(4)[11,15]) 9322 RETURN 9324 ! 9326 Icode_put_ibkpt:! ! put break point info in Info$(*) 9328 Info$(4)[11,15]=VAL$(Bkpt_obj_addr) 9330 RETURN 9332 ! 9334 Icode_trc_init: ! This subroutine is used to init the program control 9336 C_nop=61 ! section of the debugger 9338 F_pause=133 9340 GOSUB Icode_get_ibkpt 9342 RETURN 9344 ! 9346 ! ********************** INIT *********************************** 9348 ! 9350 ! This subroutine is used to initialize the debugger for debug mode. 9352 ! For format of Info$(*), see assembler documentation. 9354 ! 9356 ! ********************************************************************* 9358 ! 9360 Icode_dbg_init:! 9362 IF NOT FNIcode_info_ok(Info$(*),Error_string$) THEN GOSUB Icode_dbg_err 9364 ! 9366 ON ERROR GOTO Icode_dbg_ierr ! If error, then assume it is an 9368 ! Info$ format error. 9370 Info_info=VAL(Info$(0)[1,5]) ! What was Info_info during assembly 9372 IF Info_info<>2 THEN 9374 Error_string$="ICODE program not assembled with Info_info = 2" 9376 GOTO Icode_dbg_err 9378 END IF 9380 ! 9382 Prog_id=VAL(Info$(0)[6,10]) 9384 IF Prog_id=-1 THEN 9386 Error_string$="ICODE program not downloaded" 9388 GOTO Icode_dbg_err 9390 END IF 9392 ! 9394 GOSUB Icode_blks_init ! init display block code 9396 GOSUB Icode_vars_init ! init variable code 9398 GOSUB Icode_src_init ! init display source code 9400 GOSUB Icode_hist_init ! init history code 9402 GOSUB Icode_trc_init ! init program control code 9404 ! 9406 Obj_size=VAL(Info$(1)[11,15]) 9408 ! 9410 OFF ERROR 9412 ! 9414 ! During the initialization of the debugger, Info$(*) is access many 9416 ! times. If an error occurs during this section of code, then it is 9418 ! assumed, that the problem is with the format of Info$(*). This 9420 ! should not happen unless there is an assembler/debugger (never), or 9422 ! the user has screwed around with the Info$(*) array. 9424 ! 9426 IF 0 THEN 9428 Icode_dbg_ierr:OFF ERROR 9430 Error_string$="Invalid Info$(*) array format" 9432 GOSUB Icode_dbg_err 9434 END IF 9436 ! 9438 S_width=FNLib_crt_width 9440 S_height=FNLib_crt_height 9442 ! 9444 RETURN ! Icode_dbg_init 9446 ! 9448 ! This subroutine is used to see if the last I/O with the HP3565S 9450 ! went well. If not then an error is displayed to the user and 9452 ! the debugger is exited. 9454 ! 9456 Icode_hw_err_ck:! 9458 IF FNHw_io_error THEN 9460 Error_string$="Hardware I/O timeout error." 9462 GOTO Icode_dbg_err ! control will never be returned to the caller 9464 END IF 9466 RETURN 9468 ! 9470 ! Input: Error_string$ 9472 ! 9474 ! This subroutine is used if a really bad thing happens to the 9476 ! debugger. Note that this routine will pause the running BASIC 9478 ! program, and if continued, exit the debugger. 9480 ! 9482 Icode_dbg_err:! 9484 Icode_exec_err("Icode_debug: "&Error_string$) 9486 DISP "Debugger says 'OOPS' - hit <continue> to exit Icode_debug" 9488 PAUSE 9490 DISP 9492 SUBEXIT 9494 RETURN 9496 ! 9498 ! This subroutine is used by the soft key routines. If an unused 9500 ! key is pressed, this this routine is called. 9502 ! 9504 Icode_dbg_dmy:RETURN 9506 ! 9508 SUBEND ! end if Icode_debug 9510 ! 9512 Icode_inpt_num:SUB Icode_inpt_num(Prompt_string$,INTEGER Inpt_num,Null_flag,Error_flag,OPTIONAL Inpt_str$) 9514! 9516! This subprogram is used by the debugger to enter an integer number. 9518! The user is prompted with the string parameter Prompt_string$. If the 9520! user does not enter a string (just hit return), then Null_flag is set 9522! true. If an error occurs during input, then Error_flag is set true. 9524! If the string entered by the user is not a valid decimal or hex number, 9526! and the OPTIONAL parameter Inpt_str$ is present, then Inpt_str$ is 9528! returns with the user input string. 9530! 9532 DIM Temp$[100] 9534 Error_flag=0 9536 Null_flag=0 9538 IF NPAR=5 THEN Inpt_str$="" 9540 DISP Prompt_string$; 9542 LINPUT "",Temp$ 9544 Temp$=TRIM$(Temp$) 9546 IF Temp$="" THEN 9548 Null_flag=1 9550 ELSE 9552 ON ERROR GOTO Icode_dbg_oops 9554 IF Temp$[1,1]="$" THEN 9556 Inpt_num=DVAL(Temp$[2],16) 9558 ELSE 9560 Inpt_num=VAL(Temp$) 9562 END IF 9564 IF 0 THEN 9566 Icode_dbg_oops:! 9568 IF NPAR=5 THEN 9570 Inpt_str$=UPC$(TRIM$(Temp$)) 9572 Error_flag=1 9574 ELSE 9576 Error_flag=1 9578 Inpt_num=0 9580 BEEP 9582 DISP "***** Invalid numerical entry *****" 9584 WAIT 3 9586 END IF 9588 END IF 9590 OFF ERROR 9592 END IF 9594 SUBEND 9596 ! 9598 Icode_inpt_str:SUB Icode_inpt_str(Prompt_string$,Inpt_str$) 9600! 9602! This subprogram is used to prompt the user and enter a string from the 9604! user. The user is prompted with Prompt_string$ and the caller is 9606! returned Inpt_str$. 9608! 9610 DISP Prompt_string$; 9612 LINPUT "",Inpt_str$ 9614 Inpt_str$=UPC$(TRIM$(Inpt_str$)) 9616 SUBEND 9618 ! 9620 Icode_asc_str:DEF FNIcode_asc_str$(INTEGER Sixteen_bit_num) 9622! 9624! This function is used to convert a 16 bit integer into two characters. 9626! The Hi and Lo order bits are each converted into their ascii 9628! ascii representation. An ascii representation of a control or non 9630! printable character is replaces with a '.'. 9632! 9634 DIM Temp$[2] 9636 INTEGER Hi,Lo 9638 Hi=Sixteen_bit_num DIV 256 9640 Lo=Sixteen_bit_num MOD 256 9642 IF Hi>=32 AND Hi<=126 THEN 9644 Temp$=CHR$(Hi) 9646 ELSE 9648 Temp$="." 9650 END IF 9652 IF Lo>=32 AND Lo<=126 THEN 9654 Temp$[2]=CHR$(Lo) 9656 ELSE 9658 Temp$[2]="." 9660 END IF 9662 RETURN Temp$ 9664 FNEND