Chip,
While processing the skip routines I found that the length of the mask in some instances is > 22 although in fact because the skip values > 22 were all '0's so in fact it is OK.
So my question:
Should I just truncate the skip mask to 22 providing the values > 32 are all 0's ? This would be my choice
Chip,
While processing the skip routines I found that the length of the mask in some instances is > 22 although in fact because the skip values > 22 were all '0's so in fact it is OK.
So my question:
Should I just truncate the skip mask to 22 providing the values > 32 are all 0's ? This would be my choice
The skip pattern only needs to involve the last '1' bit. Trailing '0's can be ignored.
Chip,
Here is the next version.
Currently hardcoded - Input file is "C:/P2/Spin2/source.spin2" and output file is "source_execf.spin2"
I've included your interpreter source (no tabs) with lines modified marked with *RR and *RRx. Comment lines marking start and end of blocks are not marked.
I've allowed for a-z and A-Z but only in the first 52 columns. This means for >26 the spaces between columns need to be removed. Perhaps I should allow for 52 columns with spaces between ie check for 104 columns?
See next post for questions regarding the lines beginning with the
* label "callobj
* label "una_iso" marked with my comment *RRx
Here is a sample of the output file:
'''~------------------------------------------------------------------------------
''hub_im getnib ad,pa,#0 'a b a: setup long[vbase][0..15]
''hub_ap rfvar ad '| | c d e f g h i j k l m n o p q r s t b: setup long[dbase][0..15]
''hub_pp popa ad '| | | | | | | | | | | | | | | | | | | | u v w c: setup byte[pbase + rfvar]
'' ' d: setup byte[vbase + rfvar]
'' shl x,#2 '| | | | | | | | | | | | | | | | | r s t | | w e: setup byte[dbase + rfvar]
'' shl x,#1 '| | | | | | | | | | | l m n | | | | | | | v | f: setup byte[pbase + rfvar][pop index]
'' add ad,x '| | | | | f g h | | | l m n | | | r s t u v w g: setup byte[vbase + rfvar][pop index]
'' shl ad,#2 'a b | | | | | | | | | | | | | | | | | | | | | h: setup byte[dbase + rfvar][pop index]
'' ' i: setup word[pbase + rfvar]
'' add ad,pbase '| | c | | f | | i | | l | | o | | r | | | | | j: setup word[vbase + rfvar]
'' add ad,vbase 'a | | d | | g | | j | | m | | p | | s | | | | k: setup word[dbase + rfvar]
'' add ad,dbase '| b | | e | | h | | k | | n | | q | | t | | | l: setup word[pbase + rfvar][pop index]
'' ' m: setup word[vbase + rfvar][pop index]
''hub_p mov ad,x '| | | | | | | | | | | | | | | | | | | | | | | x y z n: setup word[dbase + rfvar][pop index]
'' popa x '| | | | | f g h | | | l m n | | | r s t u v w x y z o: setup long[pbase + rfvar]
'' ' p: setup long[vbase + rfvar]
'' mov rd,rd_long 'a b | | | | | | | | | | | | o p q r s t | | w | | z q: setup long[dbase + rfvar]
'' mov wr,wr_long 'a b | | | | | | | | | | | | o p q r s t | | w | | z r: setup long[pbase + rfvar][pop index]
'' mov sz,#31 'a b | | | | | | | | | | | | o p q r s t | | w | | z s: setup long[vbase + rfvar][pop index]
'' ' t: setup long[dbase + rfvar][pop index]
'' mov rd,rd_byte '| | c d e f g h | | | | | | | | | | | | u | | x | | u: setup byte[pop base][pop index]
'' mov wr,wr_byte '| | c d e f g h | | | | | | | | | | | | u | | x | | v: setup word[pop base][pop index]
'' mov sz,#7 '| | c d e f g h | | | | | | | | | | | | u | | x | | w: setup long[pop base][pop index]
'' ' x: setup byte[pop address]
'' mov rd,rd_word '| | | | | | | | i j k l m n | | | | | | | v | | y | y: setup word[pop address]
'' mov wr,wr_word '| | | | | | | | i j k l m n | | | | | | | v | | y | z: setup long[pop address]
'' mov sz,#15 '| | | | | | | | i j k l m n | | | | | | | v | | y |
''
'' _ret_ setq2 #$160 'a b c d e f g h i j k l m n o p q r s t u v w x y z (next bytecode is variable operator)
'''~~------------------------------------------------------------------------------
hub_im_skip_a = hub_im | %0111111000111010111110 << 10 '
hub_im_skip_b = hub_im | %0111111000110110111110 << 10 '
hub_ap_skip_c = hub_ap | %011100011111110111110 << 10 '
hub_ap_skip_d = hub_ap | %011100011111101111110 << 10 '
hub_ap_skip_e = hub_ap | %011100011111011111110 << 10 '
hub_ap_skip_f = hub_ap | %011100011101110101110 << 10 '
hub_ap_skip_g = hub_ap | %011100011101101101110 << 10 '
hub_ap_skip_h = hub_ap | %011100011101011101110 << 10 '
hub_ap_skip_i = hub_ap | %000011111111110111110 << 10 '
hub_ap_skip_j = hub_ap | %000011111111101111110 << 10 '
hub_ap_skip_k = hub_ap | %000011111111011111110 << 10 '
hub_ap_skip_l = hub_ap | %000011111101110100110 << 10 '
hub_ap_skip_m = hub_ap | %000011111101101100110 << 10 '
hub_ap_skip_n = hub_ap | %000011111101011100110 << 10 '
hub_ap_skip_o = hub_ap | %011111100011110111110 << 10 '
hub_ap_skip_p = hub_ap | %011111100011101111110 << 10 '
hub_ap_skip_q = hub_ap | %011111100011011111110 << 10 '
hub_ap_skip_r = hub_ap | %011111100001110101010 << 10 '
hub_ap_skip_s = hub_ap | %011111100001101101010 << 10 '
hub_ap_skip_t = hub_ap | %011111100001011101010 << 10 '
hub_pp_skip_u = hub_pp | %01110001110111110110 << 10 '
hub_pp_skip_v = hub_pp | %00001111110111110010 << 10 '
hub_pp_skip_w = hub_pp | %01111110000111110100 << 10 '
hub_p_skip_x = hub_p | %011100011100 << 10 '
hub_p_skip_y = hub_p | %000011111100 << 10 '
hub_p_skip_z = hub_p | %011111100000 << 10 '
''
This causes an error because the columns contain vertical space(s). Not sure what to do here?
'''~------------------------------------------------------------------------------
''callobj rfvar w 'a b c d i j k l get obj into w
''callsub rfvar v 'a b c d e f i j k l m n get sub into v
'' getptr pb 'a b c d e f i j k l m n get updated ptr
'' jmp #callh 'a b c d | f i j k l m n continue in hub
'' jmp #callsubh ' e continue in hub ('call sub' is optimized)
''callptr jmp #callptrh ' g continue in hub
''
''
''callgo rdfast #0,x 'a b c d e f g h return from hub, start new bytecode read
'' rfvar x 'a b c d e f g h get locals
'' _ret_ add ptra,x 'a b c d e f g h point stack past parameters+results+locals
'''~~------------------------------------------------------------------------------
** mask invalid: callobj_skip_a = callobj | %000 0000 << 10 '
** mask invalid: callobj_skip_b = callobj | %000 0000 << 10 '
** mask invalid: callobj_skip_c = callobj | %000 0000 << 10 '
** mask invalid: callobj_skip_d = callobj | %000 0000 << 10 '
** mask invalid: callsub_skip_e = callsub | %000 0100 << 10 '
** mask invalid: callsub_skip_f = callsub | %000 000 << 10 '
callptr_skip_g = callptr | %0000 << 10 '
callgo_skip_h = callgo | %000 << 10 '
callobj_skip_i = callobj | %0000 << 10 '
callobj_skip_j = callobj | %0000 << 10 '
callobj_skip_k = callobj | %0000 << 10 '
callobj_skip_l = callobj | %0000 << 10 '
callsub_skip_m = callsub | %000 << 10 '
callsub_skip_n = callsub | %000 << 10 '
''
The following needs a bit more explanation from you regarding the columns m & n.
See following post.
You'll note I shifted those m & n columns to the right because I reject from columns that do not contain the correct identifier. eg "x" in "m" column.
'''~------------------------------------------------------------------------------
''una_iso mov w,x ' m a: !! *RRx
''una_psh pusha x ' | n b: ! push *RRx
'' alti rd ' m n c: - (neg) rd *RRx
''op_notb test x wz 'a m n d: ABS rd,!! *RRx
''op_sqrt qsqrt x,#0 '| h x x e: ENCOD SQRT *RRx
''op_log qlog x '| | i x x f: DECOD LOG *RRx
''op_exp qexp x '| | | j x x g: ONES EXP *RRx
'' muxz x,_FFFFFFFF 'a | | | x x h: SQRT !! *RRx
''op_not not x '| b | | | x x i: LOG ! *RRx
''op_neg neg x '| | c | | | x x j: EXP - *RRx
''op_abs abs x '| | | d | | | x x ABS *RRx
''op_ncod encod x '| | | | e | | | x x ENCOD *RRx
''op_dcod decod x '| | | | | f | | | x x DECOD *RRx
''op_ones ones x '| | | | | | g | | | x x ONES *RRx
'' getqx x '| | | | | | | h i j x x *RRx
'' alti wr '| | | | | | | | | | m n wr *RRx
'' ret 'a b c d e f g h i j m n m: ?= var (isolated) wr,op *RRx
'' _ret_ mov x,w ' m | n: ?= var (push) iso *RRx
'' _ret_ zerox x,sz ' n x: use a..j push *RRx
'''~~------------------------------------------------------------------------------
These are fine, and just a-j
bc_lognot long op_notb | %01111111101110 << 10 '7A !!exp (NOT exp)
bc_bitnot long op_not | %011111110_____ << 10 '7B !exp
bc_neg long op_neg | %01111110______ << 10 '7C -exp
bc_abs long op_abs | %0111110_______ << 10 '7D ABS exp
bc_encod long op_ncod | %011110________ << 10 '7E ENCOD exp
bc_decod long op_dcod | %01110_________ << 10 '7F DECOD exp
bc_ones long op_ones | %0110__________ << 10 '80 ONES exp
bc_sqrt long op_sqrt | %0101111111110_ << 10 '81 SQRT exp
bc_qlog long op_log | %010111111110__ << 10 '82 QLOG exp
bc_qexp long op_exp | %01011111110___ << 10 '83 QEXP exp
These take the value m=%%_000xxxxxxxxxxx0010 and replace the 'x' bits from a-j
bc_lognot_write long una_iso | %000111111101110010 << 10 '17 !!= var (isolated)
bc_bitnot_write long una_iso | %000111111011110010 << 10 '18 != var (isolated)
bc_neg_write long una_iso | %000111110111110010 << 10 '19 -= var (isolated)
bc_abs_write long una_iso | %000111101111110010 << 10 '1A ABS= var (isolated)
bc_encod_write long una_iso | %000111011111110010 << 10 '1B ENCOD= var (isolated)
bc_decod_write long una_iso | %000110111111110010 << 10 '1C DECOD= var (isolated)
bc_ones_write long una_iso | %000101111111110010 << 10 '1D ONES= var (isolated)
bc_sqrt_write long una_iso | %000011111111100010 << 10 '1E SQRT= var (isolated)
bc_qlog_write long una_iso | %000011111111010010 << 10 '1F QLOG= var (isolated)
bc_qexp_write long una_iso | %000011111110110010 << 10 '20 QEXP= var (isolated)
And these take the value n=%%0100xxxxxxxxxxx000_ and replace the 'x' bits from a-j
bc_lognot_write_push long una_psh | %010011111110111000 << 10 '3B !!= var (push)
bc_bitnot_write_push long una_psh | %010011111101111000 << 10 '3C != var (push)
bc_neg_write_push long una_psh | %010011111011111000 << 10 '3D -= var (push)
bc_abs_write_push long una_psh | %010011110111111000 << 10 '3E ABS= var (push)
bc_encod_write_push long una_psh | %010011101111111000 << 10 '3F ENCOD= var (push)
bc_decod_write_push long una_psh | %010011011111111000 << 10 '40 DECOD= var (push)
bc_ones_write_push long una_psh | %010010111111111000 << 10 '41 ONES= var (push)
bc_sqrt_write_push long una_psh | %010001111111110000 << 10 '42 SQRT= var (push)
bc_qlog_write_push long una_psh | %010001111111101000 << 10 '43 QLOG= var (push)
bc_qexp_write_push long una_psh | %010001111111011000 << 10 '44 QEXP= var (push)
I can see what needs to happen. Just looking at how to express this in the source so that code can perform the exercise.
OK, I have the 'x' working. There were two complications...
* obviously catering for the 'x'
* catering for the case where the first instruction was an 'x' case but was in fact a different letter (m & n in the cases below)
So here are those examples. Haven't done the combinations of m & n with a-j..
'''~------------------------------------------------------------------------------
''una_iso mov w,x ' m a: !! *RRx
''una_psh pusha x ' | n b: ! push *RRx
'' alti rd ' m n c: - (neg) rd *RRx
''op_notb test x wz 'a m n d: ABS rd,!! *RRx
''op_sqrt qsqrt x,#0 '| h x x e: ENCOD SQRT *RRx
''op_log qlog x '| | i x x f: DECOD LOG *RRx
''op_exp qexp x '| | | j x x g: ONES EXP *RRx
'' muxz x,_FFFFFFFF 'a | | | x x h: SQRT !! *RRx
''op_not not x '| b | | | x x i: LOG ! *RRx
''op_neg neg x '| | c | | | x x j: EXP - *RRx
''op_abs abs x '| | | d | | | x x ABS *RRx
''op_ncod encod x '| | | | e | | | x x ENCOD *RRx
''op_dcod decod x '| | | | | f | | | x x DECOD *RRx
''op_ones ones x '| | | | | | g | | | x x ONES *RRx
'' getqx x '| | | | | | | h i j x x *RRx
'' alti wr '| | | | | | | | | | m n wr *RRx
'' ret 'a b c d e f g h i j m n m: ?= var (isolated) wr,op *RRx
'' _ret_ mov x,w ' m | n: ?= var (push) iso *RRx
'' _ret_ zerox x,sz ' n x: use a..j push *RRx
'''~~------------------------------------------------------------------------------
op_notb_skip_a = op_notb | %01111111101110___ << 10 '
op_not_skip_b = op_not | %011111110________ << 10 '
op_neg_skip_c = op_neg | %01111110_________ << 10 '
op_abs_skip_d = op_abs | %0111110__________ << 10 '
op_ncod_skip_e = op_ncod | %011110___________ << 10 '
op_dcod_skip_f = op_dcod | %01110____________ << 10 '
op_ones_skip_g = op_ones | %0110_____________ << 10 '
op_sqrt_skip_h = op_sqrt | %0101111111110____ << 10 '
op_log_skip_i = op_log | %010111111110_____ << 10 '
op_exp_skip_j = op_exp | %01011111110______ << 10 '
una_iso_skip_m = una_iso | %000xxxxxxxxxxx0010 << 10 '
una_psh_skip_n = una_psh | %0100xxxxxxxxxxx000_ << 10 '
''
'''~------------------------------------------------------------------------------
''sha_mod mov w,x 'a b c d e i j x x a: >> *RRx
''rev_mod not w,x '| | | | | f g h | | x x b: << *RRx
'' alti rd '| | | | | | | | | | m n c: SAR rd *RRx
'' popa x 'a b c d e f g h i j m n d: ROR rd,op *RRx
'' rev x '| | | | | f | | | | x x e: ROL REV *RRx
'' shl x,w '| b | | | | g h | | x x f: REV << *RRx
'' shr x,w 'a | | | | f g | | | x x g: ZEROX >> *RRx
'' sar x,w '| | c | | | | h | | x x h: SIGNX SAR *RRx
'' ror x,w '| | | d | | | | | | x x i: + ROR *RRx
'' rol x,w '| | | | e | | | | | x x j: - ROL *RRx
'' add x,w '| | | | | | | | i | x x + *RRx
'' sub x,w '| | | | | | | | | j x x - *RRx
'' alti wr '| | | | | | | | | | m n wr *RRx
'' ret 'a b c d e f g h i j m n m: var ?= exp (isolated) wr,op *RRx
'' _ret_ popa x ' m | n: var ?= exp (push) iso *RRx
'' _ret_ zerox x,sz ' n x: use a..j push *RRx
'''~~------------------------------------------------------------------------------
sha_mod_skip_a = sha_mod | %01111110110110 << 10 '
sha_mod_skip_b = sha_mod | %01111111010110 << 10 '
sha_mod_skip_c = sha_mod | %01111101110110 << 10 '
sha_mod_skip_d = sha_mod | %01111011110110 << 10 '
sha_mod_skip_e = sha_mod | %01110111110110 << 10 '
rev_mod_skip_f = rev_mod | %0111111010010_ << 10 '
rev_mod_skip_g = rev_mod | %0111111001010_ << 10 '
rev_mod_skip_h = rev_mod | %0111110101010_ << 10 '
sha_mod_skip_i = sha_mod | %01101111110110 << 10 '
sha_mod_skip_j = sha_mod | %01011111110110 << 10 '
sha_mod_skip_m = sha_mod | %000xxxxxxxx00xx << 10 '
sha_mod_skip_n = sha_mod | %0100xxxxxxxx00xx << 10 '
''
There is this error case. I decided not to flag it, but to insert '?' where there were spaces for the tables.
'''~------------------------------------------------------------------------------
''callobj rfvar w 'a b c d i j k l get obj into w
''callsub rfvar v 'a b c d e f i j k l m n get sub into v
'' getptr pb 'a b c d e f i j k l m n get updated ptr
'' jmp #callh 'a b c d | f i j k l m n continue in hub
'' jmp #callsubh ' e continue in hub ('call sub' is optimized)
''callptr jmp #callptrh ' g continue in hub
''
''
''callgo rdfast #0,x 'a b c d e f g h return from hub, start new bytecode read
'' rfvar x 'a b c d e f g h get locals
'' _ret_ add ptra,x 'a b c d e f g h point stack past parameters+results+locals
'''~~------------------------------------------------------------------------------
callobj_skip_a = callobj | %000??0000 << 10 '
callobj_skip_b = callobj | %000??0000 << 10 '
callobj_skip_c = callobj | %000??0000 << 10 '
callobj_skip_d = callobj | %000??0000 << 10 '
callsub_skip_e = callsub | %000?0100_ << 10 '
callsub_skip_f = callsub | %000??000_ << 10 '
callptr_skip_g = callptr | %0000_____ << 10 '
callgo_skip_h = callgo | %000______ << 10 '
callobj_skip_i = callobj | %0000 << 10 '
callobj_skip_j = callobj | %0000 << 10 '
callobj_skip_k = callobj | %0000 << 10 '
callobj_skip_l = callobj | %0000 << 10 '
callsub_skip_m = callsub | %000_ << 10 '
callsub_skip_n = callsub | %000_ << 10 '
''
Now, the other problem I found is where to terminate the columns. I fell foul of the 'x2' comment being within the table columns. No comment should be within the table columns but sometimes the program cannot determine that it has passed the end of the table columns. A simple <quote> after the columns on the first instruction line cures this. In most instances there are a number of comments lined up after the table rows and these can be detected as being the end of the table.
This is the fix: place another comment char (') in the first table line after the tables. My program treats this as the end of line for the tables in this block. It's only necessary on the first instruction line of a block, and it can actually be any non-alpha character tho ' makes sense.
'''~------------------------------------------------------------------------------
''inline_pasm setq #16-1 'a load local variables from hub into buff
'' rdlong buff,dbase 'a
'' bith v,#31 'a set flag to later restore local variables to hub
''
'' mov ptrb,pb 'a get bytecode ptr into ptrb
'' skip ##%11100100000111 'a x2 begin inline_pasm skip pattern *RR
''
''regexec_ skip ##%1111000000 '| b x2 begin REGEXEC skip pattern *RR
''regload_ mov ptrb,x '| b c get hubadr into ptrb
''
'' rdword w,ptrb++ 'a b c read start register
'' rdword y,ptrb++ 'a b c read length of pasm code, minus 1
''
'' setq y 'a b c read in code
'' altd w 'a b c
'' rdlong 0,ptrb++ 'a b c altd causes ptrb++ to inc by 4, not by (y+1)*4
''
'' _ret_ popa x '| | c REGLOAD done, pop stack
''
'' shl y,#2 'a | update bytecode ptr for inline_pasm
'' add y,ptrb 'a |
''
''call_pasm mov w,x '| | d get CALL address
'' popa x '| b d pop stack
''
'' mov y,pb '| b d save bytecode ptr
'' mov z,ptra 'a b d save ptra
''
'' call w 'a b d call pasm code (can use pa/pb/ptra/ptrb/stack, c/z=0)
''
'' testb v,#31 wc 'a b d if inline_pasm, restore local variables to hub
'' if_c setq #16-1 'a b d
'' if_c wrlong buff,dbase 'a b d
''
'' mov ptra,z 'a b d restore ptra
'' _ret_ mov pb,y 'a b d restore bytecode ptr
'''~~------------------------------------------------------------------------------
inline_pasm_skip_a = inline_pasm | %000_0000111001000001100000 << 10 '
regexec__skip_b = regexec_ | %00000000011110000000_____ << 10 '
regload__skip_c = regload_ | %0000000______ << 10 '
call_pasm_skip_d = call_pasm | %0000000000_______________ << 10 '
_skip_x = | %00____ << 10 '
''
Here is a windows .exe for the program.
It works from the command line where you can pass it the filename, or it will ask you for it. Default extension is ".spin2" if not supplied.
The output file will be in the same directory with "_execf" appended to the filename before the "." extension. the source file will not be modified.
BTW I've never built a python exe before tho it works fine on my W10 PC. I used pyinstaller to create the exe. There is a compiler for Linux and Mac available.
The practical way to handle ## cases, where two instructions are generated, would be for the user to just put an additional row of skip patterns in. That's pretty straightforward.
The practical way to handle ## cases, where two instructions are generated, would be for the user to just put an additional row of skip patterns in. That's pretty straightforward.
Do you mean those m & n cases?
Oh just realised what you meant. I didn’t notice what the x2 meant.
Yes, just found it. Would be better to define a constant for those values and then just execute a single instruction as that would be faster and not use any extra longs.
I just changed the source for the first m & n case and reran my program (as posted above - no changes). Here is the result - I left m & n in there
'''~------------------------------------------------------------------------------
''una_iso mov w,x ' m p q r s t u v w x y a: !! *RRx
''una_psh pusha x ' | | | | | | | | | | | n P Q R S T U V W X Y b: ! push *RRx
'' alti rd ' m p q r s t u v w x y n P Q R S T U V W X Y c: - (neg) rd *RRx
''op_notb test x wz 'a m p q r s t u v w x y n P Q R S T U V W X Y d: ABS rd,!! *RRx
''op_sqrt qsqrt x,#0 '| h x | | | | | | | w | | x | | | | | | | W | | e: ENCOD SQRT *RRx
''op_log qlog x '| | i x | | | | | | | | x | x | | | | | | | | X | f: DECOD LOG *RRx
''op_exp qexp x '| | | j x | | | | | | | | | y x | | | | | | | | | Y g: ONES EXP *RRx
'' muxz x,_FFFFFFFF 'a | | | x p | | | | | | | | | x P | | | | | | | | | h: SQRT !! *RRx
''op_not not x '| b | | | x | q | | | | | | | | x | Q | | | | | | | | i: LOG ! *RRx
''op_neg neg x '| | c | | | x | | r | | | | | | | x | | R | | | | | | | j: EXP - *RRx
''op_abs abs x '| | | d | | | x | | | s | | | | | | x | | | S | | | | | | ABS *RRx
''op_ncod encod x '| | | | e | | | x | | | | t | | | | | x | | | | T | | | | | ENCOD *RRx
''op_dcod decod x '| | | | | f | | | x | | | | | u | | | | x | | | | | U | | | | DECOD *RRx
''op_ones ones x '| | | | | | g | | | x | | | | | | v | | | x | | | | | | V | | | ONES *RRx
'' getqx x '| | | | | | | h i j x | | | | | | | w x y x | | | | | | | W X Y *RRx
'' alti wr '| | | | | | | | | | m p q r s t u v w x y n P Q R S T U V W X Y wr *RRx
'' ret 'a b c d e f g h i j m p q r s t u v w x y n P Q R S T U V W X Y m: ?= var (isolated) wr,op *RRx
'' _ret_ mov x,w ' m p q r s t u v w x y | | | | | | | | | | | n: ?= var (push) iso *RRx
'' _ret_ zerox x,sz ' n P Q R S T U V W X Y x: use a..j push *RRx
'''~~------------------------------------------------------------------------------
op_notb_skip_a = op_notb | %01111111101110___ << 10 '
op_not_skip_b = op_not | %011111110________ << 10 '
op_neg_skip_c = op_neg | %01111110_________ << 10 '
op_abs_skip_d = op_abs | %0111110__________ << 10 '
op_ncod_skip_e = op_ncod | %011110___________ << 10 '
op_dcod_skip_f = op_dcod | %01110____________ << 10 '
op_ones_skip_g = op_ones | %0110_____________ << 10 '
op_sqrt_skip_h = op_sqrt | %0101111111110____ << 10 '
op_log_skip_i = op_log | %010111111110_____ << 10 '
op_exp_skip_j = op_exp | %01011111110______ << 10 '
una_iso_skip_m = una_iso | %000xxxxxxxxxxx0010 << 10 '
una_iso_skip_p = una_iso | %000111111101110010 << 10 '
una_iso_skip_q = una_iso | %000111111011110010 << 10 '
una_iso_skip_r = una_iso | %000111110111110010 << 10 '
una_iso_skip_s = una_iso | %000111101111110010 << 10 '
una_iso_skip_t = una_iso | %000111011111110010 << 10 '
una_iso_skip_u = una_iso | %000110111111110010 << 10 '
una_iso_skip_v = una_iso | %000101111111110010 << 10 '
una_iso_skip_w = una_iso | %000011111111100010 << 10 '
una_iso_skip_x = una_iso | %000011111111010010 << 10 '
una_iso_skip_y = una_iso | %000011111110110010 << 10 '
una_psh_skip_n = una_psh | %0100xxxxxxxxxxx000_ << 10 '
una_psh_skip_P = una_psh | %010011111110111000_ << 10 '
una_psh_skip_Q = una_psh | %010011111101111000_ << 10 '
una_psh_skip_R = una_psh | %010011111011111000_ << 10 '
una_psh_skip_S = una_psh | %010011110111111000_ << 10 '
una_psh_skip_T = una_psh | %010011101111111000_ << 10 '
una_psh_skip_U = una_psh | %010011011111111000_ << 10 '
una_psh_skip_V = una_psh | %010010111111111000_ << 10 '
una_psh_skip_W = una_psh | %010001111111110000_ << 10 '
una_psh_skip_X = una_psh | %010001111111101000_ << 10 '
una_psh_skip_Y = una_psh | %010001111111011000_ << 10 '
''
Chip,
I think it would be best to generate new (ie separate) skip columns for those three x2 cases.
I'm wondering how to generate the pattern without the <<10 and no label. Currently I will flag an error if a skip column starts without a label present.
Any ideas?
Yes, just found it. Would be better to define a constant for those values and then just execute a single instruction as that would be faster and not use any extra longs.
I just changed the source for the first m & n case and reran my program (as posted above - no changes). Here is the result - I left m & n in there
'''~------------------------------------------------------------------------------
''una_iso mov w,x ' m p q r s t u v w x y a: !! *RRx
''una_psh pusha x ' | | | | | | | | | | | n P Q R S T U V W X Y b: ! push *RRx
'' alti rd ' m p q r s t u v w x y n P Q R S T U V W X Y c: - (neg) rd *RRx
''op_notb test x wz 'a m p q r s t u v w x y n P Q R S T U V W X Y d: ABS rd,!! *RRx
''op_sqrt qsqrt x,#0 '| h x | | | | | | | w | | x | | | | | | | W | | e: ENCOD SQRT *RRx
''op_log qlog x '| | i x | | | | | | | | x | x | | | | | | | | X | f: DECOD LOG *RRx
''op_exp qexp x '| | | j x | | | | | | | | | y x | | | | | | | | | Y g: ONES EXP *RRx
'' muxz x,_FFFFFFFF 'a | | | x p | | | | | | | | | x P | | | | | | | | | h: SQRT !! *RRx
''op_not not x '| b | | | x | q | | | | | | | | x | Q | | | | | | | | i: LOG ! *RRx
''op_neg neg x '| | c | | | x | | r | | | | | | | x | | R | | | | | | | j: EXP - *RRx
''op_abs abs x '| | | d | | | x | | | s | | | | | | x | | | S | | | | | | ABS *RRx
''op_ncod encod x '| | | | e | | | x | | | | t | | | | | x | | | | T | | | | | ENCOD *RRx
''op_dcod decod x '| | | | | f | | | x | | | | | u | | | | x | | | | | U | | | | DECOD *RRx
''op_ones ones x '| | | | | | g | | | x | | | | | | v | | | x | | | | | | V | | | ONES *RRx
'' getqx x '| | | | | | | h i j x | | | | | | | w x y x | | | | | | | W X Y *RRx
'' alti wr '| | | | | | | | | | m p q r s t u v w x y n P Q R S T U V W X Y wr *RRx
'' ret 'a b c d e f g h i j m p q r s t u v w x y n P Q R S T U V W X Y m: ?= var (isolated) wr,op *RRx
'' _ret_ mov x,w ' m p q r s t u v w x y | | | | | | | | | | | n: ?= var (push) iso *RRx
'' _ret_ zerox x,sz ' n P Q R S T U V W X Y x: use a..j push *RRx
'''~~------------------------------------------------------------------------------
op_notb_skip_a = op_notb | %01111111101110___ << 10 '
op_not_skip_b = op_not | %011111110________ << 10 '
op_neg_skip_c = op_neg | %01111110_________ << 10 '
op_abs_skip_d = op_abs | %0111110__________ << 10 '
op_ncod_skip_e = op_ncod | %011110___________ << 10 '
op_dcod_skip_f = op_dcod | %01110____________ << 10 '
op_ones_skip_g = op_ones | %0110_____________ << 10 '
op_sqrt_skip_h = op_sqrt | %0101111111110____ << 10 '
op_log_skip_i = op_log | %010111111110_____ << 10 '
op_exp_skip_j = op_exp | %01011111110______ << 10 '
una_iso_skip_m = una_iso | %000xxxxxxxxxxx0010 << 10 '
una_iso_skip_p = una_iso | %000111111101110010 << 10 '
una_iso_skip_q = una_iso | %000111111011110010 << 10 '
una_iso_skip_r = una_iso | %000111110111110010 << 10 '
una_iso_skip_s = una_iso | %000111101111110010 << 10 '
una_iso_skip_t = una_iso | %000111011111110010 << 10 '
una_iso_skip_u = una_iso | %000110111111110010 << 10 '
una_iso_skip_v = una_iso | %000101111111110010 << 10 '
una_iso_skip_w = una_iso | %000011111111100010 << 10 '
una_iso_skip_x = una_iso | %000011111111010010 << 10 '
una_iso_skip_y = una_iso | %000011111110110010 << 10 '
una_psh_skip_n = una_psh | %0100xxxxxxxxxxx000_ << 10 '
una_psh_skip_P = una_psh | %010011111110111000_ << 10 '
una_psh_skip_Q = una_psh | %010011111101111000_ << 10 '
una_psh_skip_R = una_psh | %010011111011111000_ << 10 '
una_psh_skip_S = una_psh | %010011110111111000_ << 10 '
una_psh_skip_T = una_psh | %010011101111111000_ << 10 '
una_psh_skip_U = una_psh | %010011011111111000_ << 10 '
una_psh_skip_V = una_psh | %010010111111111000_ << 10 '
una_psh_skip_W = una_psh | %010001111111110000_ << 10 '
una_psh_skip_X = una_psh | %010001111111101000_ << 10 '
una_psh_skip_Y = una_psh | %010001111111011000_ << 10 '
''
Because that code is in the hub and register space is at a premium, I used AUGS/AUGS.
Chip,
I think it would be best to generate new (ie separate) skip columns for those three x2 cases.
I'm wondering how to generate the pattern without the <<10 and no label. Currently I will flag an error if a skip column starts without a label present.
Any ideas?
Something like this...
regexec_ skip ##%1111000000 '| b x2 begin REGEXEC skip pattern
...needs to be coded like this by the programmer...
regexec_ skip ##%1111000000 '| b begin REGEXEC skip pattern
'| b
There is utility in making full 32-bit skip patterns. They are useful, too.
Chip,
I think it would be best to generate new (ie separate) skip columns for those three x2 cases.
I'm wondering how to generate the pattern without the <<10 and no label. Currently I will flag an error if a skip column starts without a label present.
Any ideas?
Something like this...
regexec_ skip ##%1111000000 '| b x2 begin REGEXEC skip pattern
...needs to be coded like this by the programmer...
regexec_ skip ##%1111000000 '| b begin REGEXEC skip pattern
'| b
There is utility in making full 32-bit skip patterns. They are useful, too.
No immediate ideas on your question, though.
I wanted to perform as many error checks as possible.
So I currently check for...
* label - first column of line begins with alpha (“.” not valid for this)
* instruction - any non-space character after a label, or if no label from 2nd position to the comment character
* missing label for start of skip pattern
* missing instruction (any non-blank data before comment) with valid skip pattern
* valid skip pattern characters...
* skip columns may start with space(s)
* skip columns start with an alpha char a-z,A-Z and must have a label too
* skip columns, once started, must contain either the alpha=“0”, |=“1”, space= end of pattern, (x allowed too), and optionally may have a label and must contain an instruction
Generating the pattern...
* leading pattern spaces are replaced with underscores in the pattern
* the first valid alpha is used to locate the label, and is used...
* generate a label for the pattern by adding “_skip_” plus the alpha char of the pattern
* the label is used for the 10-bit address placeholder
* maximum pattern length is 22 characters but if > 22 patterns above are checked for all “0”. An “_” is inserted between the 22 & 23 pattern to signify >22
Now, to generate 32-bit skip masks, I think it would be better to have the header line beginning with “‘~~———“ to begin with “‘~~~——-“. This would signify that the generated bit pattern will be 32 bits without a 10-bit label. The generated label will be the same, as will all other checks.
What do you think?
Re the ##
Currently your example would cause an error because there is no valid instruction in the added line.
I think I need to check for the ## in the instruction field, and if found, insert a line with the same pattern. Do you agree?
Re m & n masks using x
I’ve changed your source to expand these columns. We have 64 pattern available. Do you think this is viable? And remove the m & n columns altogether, and thus the x usage?
There could be two ## occurrences on a single line if both D and S are long immediates. That would mean replicating the skip bits 3x for that line.
I kind of think, to keep things simple for your tool, key off and on like this, and just look at what is in the area below the pluses and above the minuses, using and verifying the + and - registrations:
'
' Constants
' ' + + + + + + + + + +
const pusha x ' a b c d e f g h i j a: constant -1..16
mov x,pa ' a | | | | | | | | | b: byte
_ret_ sub x,#bc_con_n1-511' a | | | | | | | | | c: byte!
_ret_ rfbyte x ' b | | | | | | | | d: word
rfbyte x ' c | | | g h i j e: word!
_ret_ rfword x ' | d | | | | | | f: long
rfword x ' | e | | | | | g: byte + decod
_ret_ rflong x ' | | f | | | | h: byte + decod + not
_ret_ decod x ' | | g | | | i: byte + bmask
decod x ' | | h | | j: byte + bmask + not
_ret_ bmask x ' | | | i |
bmask x ' | | | j
_ret_ not x ' c e h j
' - - - - - - - - - -
It's vital to track TAB characters along the way, too.
Here is what I've done for the ## case. It also includes an example of the bitmask size identified in the header.
I'll fix for the case of two sets of ## in the same instruction (forgot about that)
Perhaps we can use these for the start/end block as it makes it easier to detect?
Can we keep the beginning of line '~nn (4 chars) for the start where nn=22 for a 22-bit mask with label, and '~32 for a 32-bit mask without label?
I'll check for this plus the additional sequence ' + + + (7 chars).
For the end sequence I'll check for '~ -- (4 chars) plus the sequence ' - - - (7 chars)
I need the skip mask size in order to determine if a label is to be used and the mask <<10.
'~22 ' + + +
'~32 ' + + +
'~-- ' - - -
I don't need to track tabs but if I find them I expand out 4 spaces. I only need to align the comment block.
I output the source lines as comments before the skip definitions so you can see how they were generated. In the final version I'll provide a "-v" option to turn them on else they'll be off.
The output file should be an include file in the original source as that way the source is never modified.
Anyway, here is a sample of a 32-bit skip mask, and the ## in an instruction. Note the auto-inserted commented " not <augx placeholder> " line.
'''~32----------------------------------------------------------------------------
''callh nop 'a b f g h ' nop (instruction after branch cannot be skipped) *RRx2
''
'' add w,x '| b | g | add obj index
''
'' shl w,#3 'a b f g | get obj offsets from w
'' add w,pbase 'a b f g |
'' setq #2-1 'a b f g |
'' rdlong y,w 'a b f g | y = pbase offset, z = vbase offset
''
'' jmp #makeptr '| | f g h if method ptr, continue in hub
''
'' add pbase,y 'a b add obj offsets into pbase/vbase
'' add vbase,z 'a b
''
''callsubh pusha x 'a | c if no call index, push x to save parameter
''
''calloffh shl v,#2 'a b c d e get sub offset
'' add v,pbase 'a b c d e
'' rdlong v,v 'a b c d e get bytecode params/results/offset
''
'' mov x,v 'a b c d e convert offset to branch address
'' add x,pbase 'a b c d e
''
'' and v,##$7FF00000 'a b c d e x2 save params/results above return_address *RR
'' nop <**augx placeholder**> 'a b c d e x2 save params/results above return_address *RR
'' or pb,v 'a b c d e
''
'' mov dbase,dcall 'a b c d | set dbase to dcall
'' mov ptra,dbase 'a b c d | point to stack base
'' rdlong dcall,ptra[-1] 'a b c d | read prior dcall from stack
'' wrlong pb,ptra[-1] 'a b c d | write params/results/return_address into stack
''
'' getbyte w,pb,#3 'a b c d e point past parameters
'' shl w,#2 'a b c d e
'' add ptra,w 'a b c d e
''
'' getnib w,pb,#5 'a b c d e clear results
'' sub w,#1 wc 'a b c d e
'' if_nc setq w 'a b c d e
'' if_nc wrlong #0,ptra++ 'a b c d e points past results
''
'' jmp #callgo 'a b c d e continue in cog
'''~~------------------------------------------------------------------------------
callh_skip_a = %000000000000000000000001000010
callh_skip_b = %000000000000000000001001000000
callsubh_skip_c = %000000000000000000000_________
calloffh_skip_d = %00000000000000000000__________
calloffh_skip_e = %00000000111100000000__________
callh_skip_f = %0000010
callh_skip_g = %0000000
callh_skip_h = %0111110
''
CON public i = 2
j = 5
k = 11
private m = 1
n = 2
VAR public x,y,z
private a,b,c
The object-VAR sharing would just need some setup bytecodes:
setup byte obj.var
setup byte obj.var[index]
setup byte obj[index].var
setup byte obj[index].var[index]
setup word obj.var
setup word obj.var[index]
setup word obj[index].var
setup word obj[index].var[index]
setup long obj.var
setup long obj.var[index]
setup long obj[index].var
setup long obj[index].var[index]
compile sequence for object-var setup:
{push obj index}
{push var index}
setup bytecode
rfvar obj
rfvar var
CON* i = 2, j = 5, k = 11
CON m = 1, n = 2
VAR* x,y,x
VAR a,b,c
SUB* pulses(pin,count)
repeat count
pintoggle(pin)
pintoggle(pin)
SUB pulsesx2(pin,count)
pulses(pin, count * 2)
SUB replaces PUB/PRI, while * after the block type determines if it's public.
I think it is important to distinguish between a variable that can be read from the outside and one that can be both read and written from the outside. The lack of this distinction is one reason why C++ and Java programmers often use getter/setter methods instead of public instance variables. (The other reason is that a setter method can do more than just set the variable (usually to notify some other code about the changed variable))
Comments
While processing the skip routines I found that the length of the mask in some instances is > 22 although in fact because the skip values > 22 were all '0's so in fact it is OK.
So my question:
Should I just truncate the skip mask to 22 providing the values > 32 are all 0's ? This would be my choice
The skip pattern only needs to involve the last '1' bit. Trailing '0's can be ignored.
Here is the next version.
Currently hardcoded - Input file is "C:/P2/Spin2/source.spin2" and output file is "source_execf.spin2"
I've included your interpreter source (no tabs) with lines modified marked with *RR and *RRx. Comment lines marking start and end of blocks are not marked.
I've allowed for a-z and A-Z but only in the first 52 columns. This means for >26 the spaces between columns need to be removed. Perhaps I should allow for 52 columns with spaces between ie check for 104 columns?
See next post for questions regarding the lines beginning with the
* label "callobj
* label "una_iso" marked with my comment *RRx
Here is a sample of the output file:
The following needs a bit more explanation from you regarding the columns m & n.
See following post.
You'll note I shifted those m & n columns to the right because I reject from columns that do not contain the correct identifier. eg "x" in "m" column.
OK, I can see what the m & n does... These are fine, and just a-j These take the value m=%%_000xxxxxxxxxxx0010 and replace the 'x' bits from a-j And these take the value n=%%0100xxxxxxxxxxx000_ and replace the 'x' bits from a-j I can see what needs to happen. Just looking at how to express this in the source so that code can perform the exercise.
Maybe 'x' is not a good indicator of 'use a..z', because it's part of the set. Perhaps '#' would be better to use for that case.
* obviously catering for the 'x'
* catering for the case where the first instruction was an 'x' case but was in fact a different letter (m & n in the cases below)
So here are those examples. Haven't done the combinations of m & n with a-j..
This is the fix: place another comment char (') in the first table line after the tables. My program treats this as the end of line for the tables in this block. It's only necessary on the first instruction line of a block, and it can actually be any non-alpha character tho ' makes sense.
It works from the command line where you can pass it the filename, or it will ask you for it. Default extension is ".spin2" if not supplied.
The output file will be in the same directory with "_execf" appended to the filename before the "." extension. the source file will not be modified.
BTW I've never built a python exe before tho it works fine on my W10 PC. I used pyinstaller to create the exe. There is a compiler for Linux and Mac available.
Oh just realised what you meant. I didn’t notice what the x2 meant.
I just changed the source for the first m & n case and reran my program (as posted above - no changes). Here is the result - I left m & n in there
I think it would be best to generate new (ie separate) skip columns for those three x2 cases.
I'm wondering how to generate the pattern without the <<10 and no label. Currently I will flag an error if a skip column starts without a label present.
Any ideas?
Because that code is in the hub and register space is at a premium, I used AUGS/AUGS.
Something like this...
...needs to be coded like this by the programmer...
There is utility in making full 32-bit skip patterns. They are useful, too.
No immediate ideas on your question, though.
So I currently check for...
* label - first column of line begins with alpha (“.” not valid for this)
* instruction - any non-space character after a label, or if no label from 2nd position to the comment character
* missing label for start of skip pattern
* missing instruction (any non-blank data before comment) with valid skip pattern
* valid skip pattern characters...
* skip columns may start with space(s)
* skip columns start with an alpha char a-z,A-Z and must have a label too
* skip columns, once started, must contain either the alpha=“0”, |=“1”, space= end of pattern, (x allowed too), and optionally may have a label and must contain an instruction
Generating the pattern...
* leading pattern spaces are replaced with underscores in the pattern
* the first valid alpha is used to locate the label, and is used...
* generate a label for the pattern by adding “_skip_” plus the alpha char of the pattern
* the label is used for the 10-bit address placeholder
* maximum pattern length is 22 characters but if > 22 patterns above are checked for all “0”. An “_” is inserted between the 22 & 23 pattern to signify >22
Now, to generate 32-bit skip masks, I think it would be better to have the header line beginning with “‘~~———“ to begin with “‘~~~——-“. This would signify that the generated bit pattern will be 32 bits without a 10-bit label. The generated label will be the same, as will all other checks.
What do you think?
Re the ##
Currently your example would cause an error because there is no valid instruction in the added line.
I think I need to check for the ## in the instruction field, and if found, insert a line with the same pattern. Do you agree?
Re m & n masks using x
I’ve changed your source to expand these columns. We have 64 pattern available. Do you think this is viable? And remove the m & n columns altogether, and thus the x usage?
I kind of think, to keep things simple for your tool, key off and on like this, and just look at what is in the area below the pluses and above the minuses, using and verifying the + and - registrations:
It's vital to track TAB characters along the way, too.
I'll fix for the case of two sets of ## in the same instruction (forgot about that)
Perhaps we can use these for the start/end block as it makes it easier to detect?
Can we keep the beginning of line '~nn (4 chars) for the start where nn=22 for a 22-bit mask with label, and '~32 for a 32-bit mask without label?
I'll check for this plus the additional sequence ' + + + (7 chars).
For the end sequence I'll check for '~ -- (4 chars) plus the sequence ' - - - (7 chars)
I need the skip mask size in order to determine if a label is to be used and the mask <<10.
I don't need to track tabs but if I find them I expand out 4 spaces. I only need to align the comment block.
I output the source lines as comments before the skip definitions so you can see how they were generated. In the final version I'll provide a "-v" option to turn them on else they'll be off.
The output file should be an include file in the original source as that way the source is never modified.
Anyway, here is a sample of a 32-bit skip mask, and the ## in an instruction. Note the auto-inserted commented " not <augx placeholder> " line.
For example, I'm playing around with a VGA driver and would be nice if could do:
To set the VAR section defined variable, "boxcolor", to the value $10
Instead, I currently need to create a function like "SetBoxColor" in the VGA driver as a work around....
struct and class are equivalent in C++, only struct is public by default and class is private by default.
The object-VAR sharing would just need some setup bytecodes:
KISS
I agree.
SUB replaces PUB/PRI, while * after the block type determines if it's public.