diff --git a/src/lars/qrcode.8 b/src/lars/qrcode.8 new file mode 100644 index 000000000..40f0d8c6f --- /dev/null +++ b/src/lars/qrcode.8 @@ -0,0 +1,1355 @@ + TITLE QRCODE - QR Code Generator + +%MDNUM==1 ;Numeric +%MDANUM==2 ;Alphanumeric +%MDBYTE==4 ;Bytes, 8-bit + +A=1 +B=2 +C=3 +D=4 +E=5 +F=6 +G=7 +P=17 + +DSKIC==1 +TYOC==2 + +GO: MOVE P,[-100,,PDL-1] + + .OPEN TYOC,[.UAO+%TJDIS,,'TTY] + .LOSE %LSSYS + + PUSHJ P,READ ;Read input. + PUSHJ P,INIT ;Compute initial things. + + MOVE A,MODE ;Encoding mode, 4 bits. + MOVEI B,4 + PUSHJ P,STORE + + MOVE B,VERSION ;Data length, number of bits depends + MOVE C,MODE ;on version and mode. + MOVE B,@LTAB(B) + MOVE A,LENGTH + PUSHJ P,STORE + + MOVE A,[440700,,MESSAGE] ;Store data. + MOVE B,MODE + PUSHJ P,@STAB(B) + + MOVEI A,0 ;Termination block, four 0 bits. + MOVEI B,4 + PUSHJ P,STORE + + PUSHJ P,PAD ;Pad out to octet boundary + PUSHJ P,FILL ;Fill the rest with alternating 236. and 17. + PUSHJ P,REDSOL ;Compute Reed-Solomon error correcting codes. + PUSHJ P,INTERL ;Interleave bytes from all blocks. + PUSHJ P,FUNC ;Draw function patterns. + PUSHJ P,ZIGZAG ;Draw output data. + PUSHJ P,EVAL ;Evaluate penalty scores. + PUSHJ P,APPLY ;Apply mask. + PUSHJ P,FORMAT ;Draw format. + PUSHJ P,PAINT ;Draw QR code on TV display. + + .VALUE [ASCIZ /:KILLî/] ;Exit silently. + +RFN"$$RFN==1 +.INSRT DSK:SYSENG;RFN + +CMD: BLOCK 100 + +RSIXTP: POPJ P, + +;Read input. +READ: .SUSET [.ROPTION,,A] + TLNN A,%OPDDT ;Superior better be DDT. + JRST READ1 + TLNN A,%OPCMD ;Check if there is a command line. + JRST READ1 + .BREAK 12,[..RPFI,,DEV] ;Get filename defaults. + MOVE A,SNAME + EXCH A,FN2 ;They're a different order. + EXCH A,FN1 + MOVEM A,SNAME + .BREAK 12,[..RJCL,,CMD] ;Get command line. + MOVEI B,DEV + MOVE D,[440700,,CMD] + PUSHJ P,RFN"RFN ;Parse file name. + JRST READ3 + +READ1: MOVE A,[440700,,[ASCIZ /Type data, terminated by ^C +/]] +READ2: ILDB B,A + JUMPE B,READ3 + .IOT TYOC,B + JRST READ2 + +READ3: .CALL [ SETZ ;Open input file. + SIXBIT /OPEN/ + MOVE [.UAI,,DSKIC] + MOVE DEV + MOVE FN1 + MOVE FN2 + SETZ SNAME ] + .LOSE %LSFIL + MOVE A,[440700,,MESSAGE] + MOVEM A,PTR + SETZM LENGTH' + MOVEI A,%MDNUM +READ4: .IOT DSKIC,B ;Read data from input. + CAIE B,^C ;TTY end of input. + SKIPGE B ;File end of input. + POPJ P, + IDPB B,PTR + PUSHJ P,CHECK ;Check data mode. + MOVEM A,MODE + AOS C,LENGTH ;Keep track of data length. + CAIGE C,MAX ;Maximum size of input buffer. + JRST READ4 + POPJ P, + +DEV: SIXBIT /TTY/ +FN1: 0 +FN2: 0 +SNAME: 0 + +CHECK: CAIL B,"0 ;Check whether a character fits + CAILE B,"9 ;in numerical, alphanumerical, or + MOVEI A,%MDANUM ;byte mode. + PUSHJ P,ANUM + MOVEI A,%MDBYTE + POPJ P, + +;Compute initial things. +INIT: MOVE A,[440100,,DATA] + MOVEM A,PTR' + + SETZM VERSION + +INIT1: AOS A,VERSION + CAILE A,40. + .VALUE [ASCIZ /:Data doesn't fit in a single QR code. +/] + IMULI A,4 ;Compute size from version. + ADDI A,17. + MOVEM A,SIZE' + + MOVE B,LEVEL + MOVE C,VERSION + MOVE A,@BTAB(B) ;Number of blocks. + MOVEM A,BLOCKS' + MOVE A,@ETAB(B) ;Number of ECC codewords per block. + MOVEM A,ECCS' + + MOVE A,SIZE ;Compute data capacity in bits. + IMUL A,A + SUBI A,3*64. ;Three finders, including separators. + SUBI A,31. ;Format information. + MOVE B,VERSION + SKIPE VTAB(B) + SUBI A,2*18. ;Version information. + MOVE B,SIZE + SUBI B,2*8 + IMULI B,2 + SUB A,B ;Two timing patterns. + MOVE B,VERSION + SKIPE ATAB(B) + JRST [ IDIVI B,7 + ADDI B,1 + MOVEI C,-1(B) + IMUL B,B + IMULI B,25. + SUB A,B ;Full alignment patterns. + IMULI C,40. + SUB A,C ;Alignment patterns that intersect + JRST .+1 ] ;with timing patterns. + MOVEM A,BITS' + + IDIVI A,8 ;Compute number of data bytes, + MOVE B,BLOCKS ;excluding error correction codes. + IMUL B,ECCS + SUB A,B + MOVEM A,BYTES' + + IMULI A,8 ;Check whether data fits. + SUBI A,4+4 ;Start code and stop code. + MOVE B,VERSION + MOVE C,MODE + SUB A,@LTAB(B) + MOVE B,LENGTH ;Convert number of message characters + PUSHJ P,@CTAB(C) ;to number of bits, depending on mode. + SUB A,B + CAIGE A,0 + JRST INIT1 ;Out of space, try a larger version. + + MOVEI A,454. ;Scale symbol to fit on display. + SUB A,MARGIN + SUB A,MARGIN + IDIV A,SIZE + MOVEM A,SCALE ;Better not exceed 32. + + MOVN A,SCALE ;Compute pixel mask for squares. + MOVSI B,400000 + ASH B,1(A) + MOVEM B,PIXELS' + + SETZM DATA ;Clear data and output. + MOVE A,[DATA,,DATA+1] + BLT A,EDAT + SETZM OUTPUT + MOVE A,[OUTPUT,,OUTPUT+1] + BLT A,EOUT + + POPJ P, + +;Pad out data to an octet boundary. +PAD: LDB B,[360300,,PTR] + HRRZ A,PTR + SUBI A,DATA + TRNN A,1 + TRC B,4 + MOVEI A,0 + PUSHJ P,STORE + POPJ P, + +;Fill remaining data up to maximum capacity. +FILL: HRRZ A,PTR + SUBI A,DATA ;Number of full words of data. + IMULI A,36. ;Number of bits. + LDB B,[360600,,PTR] + SUBI A,-36.(B) ;Add number of bits in last word. + HRRZS A + IDIVI A,8 ;Total number of octets of data. + MOVE C,BYTES ;Data capacity. + SUB C,A ;Number of octets to fill. +FILL1: SOJL C,CPOPJ + MOVEI A,236. + MOVEI B,8 + PUSHJ P,STORE + SOJL C,CPOPJ + MOVEI A,17. + MOVEI B,8 + PUSHJ P,STORE + JRST FILL1 + +;Compute Reed-Solomon error correcting codes. +REDSOL: PUSHJ P,RSDIV ;Compute divisor for ECC. + MOVE A,[440400,,DATA] + MOVEM A,PTR + MOVE A,BYTES + IDIV A,BLOCKS ;Data block size. + MOVEM B,LONG' ;Number of long data blocks. + MOVE B,BLOCKS + SUB B,LONG ;Number of short data blocks. + MOVEM B,SHORT' + MOVEI C,ECC ;Start of ECC data. +REDSO1: PUSHJ P,RSREM + ADD C,ECCS ;Next ECC block. + SOJG B,REDSO1 + SKIPN B,LONG ;Now do the long blocks. + POPJ P, + ADDI A,1 ;Data is one byte longer. +REDSO2: PUSHJ P,RSREM + ADD C,ECCS ;Next ECC block. + SOJG B,REDSO2 + POPJ P, + +;Interleave bytes from all blocks, first data then ECC. +INTERL: MOVE A,BYTES + IDIV A,BLOCKS ;Data block size. + MOVE B,[440400,,OUTPUT] + MOVEM B,PTR + MOVN B,BYTES + ADD B,LONG ;Skip remainder of long data blocks. + HRLZS B +INTRL1: PUSHJ P,GETDAT ;Get data byte. + ROT C,-4 + IDPB C,PTR + ROT C,4 + IDPB C,PTR + AOBJN B,INTRL1 + + MOVN C,LONG ;Remainder of long data blocks. + JUMPE C,INTRL3 + HRL B,C + ADD B,SHORT ;Skip over indices for short blocks. +INTRL2: PUSHJ P,GETDAT + ROT C,-4 + IDPB C,PTR + ROT C,4 + IDPB C,PTR + AOBJN B,INTRL2 +INTRL3: + + MOVE A,ECCS + MOVN B,BLOCKS + IMUL B,A ;Total number of ECC bytes. + HRLZS B +INTRL4: PUSHJ P,GETECC ;Get ECC byte from a block. + ROT C,-4 + IDPB C,PTR + ROT C,4 + IDPB C,PTR + AOBJN B,INTRL4 + + POPJ P, + +;Get one byte of data from a block. Block size in A, +;byte index in B. Return data in C. +GETDAT: PUSH P,A + PUSH P,B + HRRZS B + IDIV B,BLOCKS ;Divide index by number of blocks. + CAML C,SHORT + ADDI A,1 + IMUL C,A ;Block size. + ADD B,C ;Byte index into data. + IMULI B,8 ;Bit index. + IDIVI B,36. + MOVEI A,DATA(B) ;Word address. + MOVNI B,-36.(C) ;Bit position in word. + LSH B,12. + TLO A,400(B) ;Convert to 4-bit byte pointer. + ILDB B,A ;Load two nybbles. + ILDB C,A + LSH B,4 + ADD C,B ;Combine to byte. + POP P,B + POP P,A + POPJ P, + +;Get one byte of ECC from a block. Block size in A, index in B. +GETECC: PUSH P,B + HRRZS B + IDIV B,BLOCKS ;Divide index by number of blocks. + IMUL C,A ;Block size. + ADD B,C + MOVE C,ECC(B) + POP P,B + POPJ P, + +;Compute Reed-Solomon ECC divisor. +RSDIV: SETZM DIVISOR + MOVE B,[DIVISOR,,DIVISOR+1] + BLT B,DIVISOR+30.-1 + MOVE A,ECCS ;Divisor degree. + MOVEI C,1 + MOVEM C,DIVISOR-1(A) +RSDIV1: MOVN B,ECCS + HRLZS B +RSDIV2: MOVE D,DIVISOR(B) + PUSHJ P,RSMUL + ADDI B,1 + CAMGE B,ECCS + XOR E,DIVISOR(B) + SUBI B,1 + MOVEM E,DIVISOR(B) + AOBJN B,RSDIV2 + MOVEI D,2 + PUSHJ P,RSMUL + MOVE C,E + SOJG A,RSDIV1 + POPJ P, + +;Multiply for Reed-Solomon ECC, terms in C and D, result in E. +RSMUL: MOVEI E,0 + MOVEI F,200 +RSMUL1: LSH E,1 + TRNE E,400 + XORI E,435 + TRNE C,(F) + XOR E,D + LSH F,-1 + JUMPN F,RSMUL1 + POPJ P, + +;Compute ECC codewords. Data length in A, write result to C. +RSREM: PUSH P,A + PUSH P,B + PUSH P,C + SETZM (C) ;Clear result array. + MOVEI D,1(C) + HRL D,C + ADD C,ECCS + SUBI C,1 + BLT D,(C) + MOVE C,(P) +RSREM1: ILDB E,PTR ;Get data byte. + ILDB F,PTR + LSH E,4 + ADD E,F + XOR E,(C) ;Add first result element. + PUSHJ P,SHIFT ;Shift array. + PUSHJ P,MULIFY + SOJG A,RSREM1 + POP P,C + POP P,B + POP P,A + POPJ P, + +;Shift array. +SHIFT: PUSH P,A + PUSH P,B + MOVN A,ECCS + HRLI A,1(A) + HRR A,C +SHIFT1: MOVE B,1(A) + MOVEM B,(A) + AOBJN A,SHIFT1 + SETZM (A) ;Clear last element. + POP P,B + POP P,A + POPJ P, + +;Multiply with E, starting at C. +MULIFY: PUSH P,A + PUSH P,B + PUSH P,C + PUSH P,E + MOVN A,ECCS + HRL A,A + HRR A,C + MOVEI B,DIVISOR +MULIF1: MOVE C,(B) ;Get byte from divisor. + MOVE D,(P) ;Get factor. + PUSHJ P,RSMUL + XORM E,(A) ;Add to result. + ADDI B,1 + AOBJN A,MULIF1 + POP P,E + POP P,C + POP P,B + POP P,A + POPJ P, + +;Draw function patterns: finders, timing, aligmnent, format, version. +FUNC: SETZM IMAGE ;Clear entire image. + MOVE A,[IMAGE,,IMAGE+1] + BLT A,IMAGE+<177.*177.>-1 + + SETO C, + + MOVE A,[-7,,0] ;Draw top left finder. + MOVE B,[-7,,0] + PUSHJ P,BOX + TLC C,-1 + MOVE A,[-8,,0] + MOVEI B,7 + PUSHJ P,XLINE + MOVE A,[-8,,7] + MOVEI B,0 + PUSHJ P,YLINE + TLC C,-1 + + MOVE A,SIZE ;Draw top right finder. + SUBI A,7 + HRLI A,-7 + MOVE B,[-7,,0] + PUSHJ P,BOX + TLC C,-1 + MOVE A,SIZE + SUBI A,8 + HRLI A,-8 + PUSH P,A + MOVEI B,7 + PUSHJ P,XLINE + POP P,A + MOVEI B,0 + PUSHJ P,YLINE + TLC C,-1 + + MOVE A,[-7,,0] ;Draw bottom left finder. + MOVE B,SIZE + SUBI B,7 + HRLI B,-7 + PUSHJ P,BOX + TLC C,-1 + MOVE A,[-8,,0] + MOVE b,SIZE + SUBI b,8 + PUSH P,B + PUSHJ P,XLINE + MOVE A,[-8,,7] + POP P,B + PUSHJ P,YLINE + TLC C,-1 + + MOVE A,VERSION ;Draw alignment. + SKIPE A,ATAB(A) + PUSHJ P,ALIGN + + MOVN A,SIZE ;Draw horizontal timing. + ADDI A,16. + HRLS A + HRRI A,8 + ADDI A,6*177. + MOVEM C,IMAGE(A) + TLC C,-1 + AOBJN A,.-2 + TLC C,-1 + + MOVN A,SIZE ;Draw vertical timing. + ADDI A,16. + HRLS A + HRRI A,6 + ADDI A,8*177. + MOVEM C,IMAGE(A) + TLC C,-1 + ADDI A,176. + AOBJN A,.-3 + + PUSHJ P,FORMAT ;Draw format. + + MOVE D,VERSION ;Draw version. + SKIPE D,VTAB(D) + PUSHJ P,VERS + + POPJ P, + +;Draw output data. +ZIGZAG: MOVE A,[440100,,OUTPUT] + MOVEM A,PTR + MOVE A,SIZE + SUBI A,1 ;Skip timing pattern column. + IMUL A,SIZE + SUBI A,1 ;Start position is lower right. + MOVEM A,POS' +ZIGZA1: PUSHJ P,GETXY ;Get column and row from position. + PUSHJ P,FUNCP ;Is a function pattern there? + PUSHJ P,DOT ;No, draw a data module. + SOSL POS + JRST ZIGZA1 + POPJ P, + +;Compute matrix position from POS, return x-y in A-B. +GETXY: MOVE A,POS + IDIVI A,2 + EXCH A,B + IDIV B,SIZE + LSH B,1 + ADD A,B + CAIL A,6 + ADDI A,1 ;Skip timing pattern column. + TRNE B,2 + JRST [EXCH B,C ? POPJ P,] + MOVE B,SIZE ;Alternate up-down. + SUBI B,1(C) + POPJ P, + +;Check whether position in A-B is a function pattern. +;Return image offset in A. +FUNCP: IMULI B,177. + ADD A,B + MOVE B,IMAGE(A) + TRNE B,-1 + AOS (P) + POPJ P, + +;Draw a data bit at image offset A. +DOT: HRROI C,0 + ILDB B,PTR + TRNE B,1 + MOVEM C,IMAGE(A) + POPJ P, + +;Evaluate penalty scores for all masks. +EVAL: MOVEI A,7 + HRLZM A,SCORE' ;Lowest score so far. +EVAL1: MOVEM A,MASK + PUSHJ P,FORMAT ;Draw format. + PUSHJ P,APPLY ;Apply mask for scoring. + PUSHJ P,EVAL3 ;Compute score. + MOVE A,PENALTY + CAML A,SCORE + JRST EVAL2 + MOVEM A,SCORE ;Lower score, this is the + MOVE A,MASK ;best mask so far. + MOVEM A,BEST' +EVAL2: PUSHJ P,APPLY ;Remove current mask. + SOSL A,MASK + JRST EVAL1 ;Try next mask. + MOVE A,BEST + MOVEM A,MASK + POPJ P, + +;Compute penalty score for current mask. +EVAL3: SETZM PENALTY' + SETZM TOTAL' + MOVN A,SIZE + HRLZS A + PUSH P,A + +EVAL4: MOVE B,(P) + PUSHJ P,BEGIN ;Initialize run check. + MOVEI C,1 +EVAL5: PUSHJ P,RUN ;Check for run of five or more. + PUSHJ P,FINDISH ;Check for finder-like pattern. + PUSHJ P,TALLY ;Compute total number of dark modules. + AOBJN B,EVAL5 + EXCH A,B ;Now check in the other direction. + MOVE A,(P) + PUSHJ P,BEGIN + MOVEI C,177. +EVAL5B: PUSHJ P,RUN + PUSHJ P,FINDISH + AOBJN A,EVAL5B + EXCH A,B + AOBJN A,EVAL4 + + MOVE A,[1,,] + ADDB A,(P) +EVAL6: MOVE B,(P) +EVAL7: PUSHJ P,2X2 ;Check for 2x2 square of same color. + AOBJN B,EVAL7 + AOBJN A,EVAL6 + POP P, + + MOVE A,TOTAL ;Penalty for deviation from + IMULI A,100. ;50% dark/light. + MOVE B,SIZE + IMUL B,B + ROTC B,-1 + ADD A,B + ROTC B,1 + IDIV A,B + SUBI A,50. + MOVMI A,A + IDIVI A,5 + IMULI A,10. + ADDM A,PENALTY + + POPJ P, + +;Initialize run check. +BEGIN: MOVEI D,0 + PUSHJ P,MODULE + SKIPA F,[DARK] + MOVEI F,LIGHT + POPJ P, + +;Check for run of five or more modules of same color. +RUN: JRST (F) ;Update run count. +RUN1: MOVEI E,3 + CAIN D,5 ;Run of five has penalty 3. + ADDM E,PENALTY + CAIL D,6 ;More than five adds 1 to pentalty. + AOS PENALTY + POPJ P, + +DARK: PUSHJ P,MODULE ;Checking for a run of dark modules. + AOJA D,RUN1 ;Still dark, increase count. + MOVEI D,1 + MOVEI F,LIGHT ;Light, clear count. + JRST RUN1 + +LIGHT: PUSHJ P,MODULE ;Checking for a run of light moules. + JRST [ MOVEI D,1 ;Dark, clear count. + MOVEI F,DARK + JRST RUN1 ] + AOJA D,RUN1 ;Still light, increase count. + +;Check for finder-like patterns. +FINDISH:CAML A,[-11.,,0] + POPJ P, + PUSH P,A + PUSHJ P,4LIGHT + JRST FIND1 + PUSHJ P,1DARK + JRST FIND1 + PUSHJ P,1LIGHT + JRST FIND1 + PUSHJ P,3DARK + JRST FIND1 + PUSHJ P,1LIGHT + JRST FIND1 + PUSHJ P,1DARK + JRST FIND1 + JRST FIND2 +FIND1: MOVE A,(P) + PUSHJ P,1DARK + JRST FIND3 + PUSHJ P,1LIGHT + JRST FIND3 + PUSHJ P,3DARK + JRST FIND3 + PUSHJ P,1LIGHT + JRST FIND3 + PUSHJ P,1DARK + JRST FIND3 + PUSHJ P,4LIGHT + JRST FIND3 +FIND2: MOVEI E,40. + ADDM E,PENALTY +FIND3: POP P,A + POPJ P, + +1DARK: PUSHJ P,MODULE + AOS (P) + ADD A,C + POPJ P, + +1LIGHT: PUSHJ P,MODULE + CAIA + AOS (P) + ADD A,C + POPJ P, + +3DARK: PUSHJ P,1DARK + POPJ P, + PUSHJ P,1DARK + POPJ P, + PUSHJ P,1DARK + POPJ P, + AOS (P) + POPJ P, + +4LIGHT: PUSHJ P,1LIGHT + POPJ P, + PUSHJ P,1LIGHT + POPJ P, + PUSHJ P,1LIGHT + POPJ P, + PUSHJ P,1LIGHT + POPJ P, + AOS (P) + POPJ P, + +2X2: MOVEI C,0 ;Check 2x2 square. + PUSHJ P,MODULE + ADDI C,1 + ADDI A,1 + PUSHJ P,MODULE + ADDI C,1 + ADDI B,1 + PUSHJ P,MODULE + ADDI C,1 + SUBI A,1 + PUSHJ P,MODULE + ADDI C,1 + SUBI B,1 + MOVEI D,3 + TRNN C,3 ;If all four are dark, or all + ADDM D,PENALTY ;four are light, add penalty 3. + POPJ P, + +TALLY: PUSHJ P,MODULE + AOS TOTAL + POPJ P, + +;Apply mask. +APPLY: MOVN A,SIZE + HRLZS A + MOVE B,A + HRLZI C,-1 + MOVEI D,IMAGE + MOVE E,MASK + PUSH P,A +APPLY1: MOVE A,(P) +APPLY2: MOVE F,(D) + TRNE F,-1 + JRST APPLY3 + PUSH P,A + PUSH P,B + HRRZS A + HRRZS B + PUSHJ P,@MTAB(E) + XORM C,(D) + POP P,B + POP P,A +APPLY3: ADDI D,1 + AOBJN A,APPLY2 + ADDI D,177. + SUB D,SIZE + AOBJN B,APPLY1 + POP P, + POPJ P, + +MTAB: MASK0 ? MASK1 ? MASK2 ? MASK3 + MASK4 ? MASK5 ? MASK6 ? MASK7 + +MASK0: ADD A,B + TRNE A,1 + AOS (P) + POPJ P, + +MASK1: TRNE B,1 + AOS (P) + POPJ P, + +MASK2: IDIVI A,3 + CAIE B,0 + AOS (P) + POPJ P, + +MASK3: ADD A,B + IDIVI A,3 + CAIE B,0 + AOS (P) + POPJ P, + +MASK4: MOVE F,B + LSH F,-1 + IDIVI A,3 + ADD A,F + TRNE A,1 + AOS (P) + POPJ P, + +MASK5: PUSH P,C + IMULB A,B + ANDI A,1 + IDIVI B,3 + ADD A,C + CAIE A,0 + AOS -1(P) + POP P,C + POPJ P, + +MASK6: PUSH P,C + IMULB A,B + IDIVI B,3 + ADD A,C + TRNE A,1 + AOS -1(P) + POP P,C + POPJ P, + +MASK7: PUSH P,C + MOVE C,A + ADD A,B + IMUL B,C + IDIVI B,3 + ADD A,C + TRNE A,1 + AOS -1(P) + POP P,C + POPJ P, + +;Draw two version patterns, 18-bit code in D. +VERS: PUSH P,D + MOVE A,[-6,,0] +VERS1: MOVE B,SIZE + SUBI B,11. + HRLI B,-3 +VERS2: TRNE D,1 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,-1 + AOBJN B,VERS2 + AOBJN A,VERS1 + + POP P,D + MOVE B,[-6,,0] +VERS3: MOVE A,SIZE + SUBI A,11. + HRLI A,-3 +VERS4: TRNE D,1 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,-1 + AOBJN A,VERS4 + AOBJN B,VERS3 + POPJ P, + +;Draw two format patterns, 15-bit code in D. +FORMAT: MOVE A,LEVEL + MOVE B,MASK + SETO C, + MOVE D,@FTAB(A) + PUSH P,D ;Draw in upper left. + MOVEI A,8 + MOVE B,[-8,,0] +FORMA0: CAMN B,[-2,,6] + ADDI B,1 + TRNE D,1 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,-1 + AOBJN B,FORMA0 + MOVE A,[-7,,0] + MOVEI B,8 +FORMA1: CAMN A,[-1,,6] + ADDI A,1 + TRNE D,100 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,1 + AOBJN A,FORMA1 + + POP P,D ;Draw in upper right. + MOVE A,SIZE + SUBI A,8 + HRLI A,-8 + MOVEI B,8 +FORMA2: TRNE D,200 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,1 + AOBJN A,FORMA2 + MOVEI A,8 ;Draw in lower left. + MOVE B,SIZE + SUBI B,8 + SETO C, + PUSHJ P,POINT + ADDI B,1 + HRLI B,-7 +FORMA3: TRNE D,200000 + TLOA C,-1 + TLZ C,-1 + PUSHJ P,POINT + LSH D,-1 + AOBJN B,FORMA3 + POPJ P, + +;Draw concentric boxes, size and position as AOBJN pointers in A and B. +BOX: PUSH P,D + PUSH P,B + PUSH P,A +BOX1: MOVE A,(P) ;Draw a dark square covering the full area. + PUSHJ P,XLINE + AOBJN B,BOX1 + TLC C,-1 + MOVE A,(P) ;Draw four light lines inside the perimeter. + ADD A,[2,,1] + MOVE B,-1(P) + ADDI B,1 + PUSHJ P,XLINE + MOVE A,(P) + ADD A,[2,,1] + MOVE B,-1(P) + HLRE D,(P) + SUBI B,2(D) + PUSHJ P,XLINE + MOVE A,(P) + ADD A,[2,,1] + MOVE B,-1(P) + ADDI B,1 + PUSHJ P,YLINE + HRRZ A,(P) + HLRE D,(P) + SUBI A,2(D) + HLL A,(P) + ADD A,[2,,0] + MOVE B,-1(P) + ADDI B,1 + PUSHJ P,YLINE + TLC C,-1 + POP P,A + POP P,B + POP P,D + POPJ P, + +;Draw a single point, x-y coordinates in A and B. +POINT: PUSH P,A + PUSH P,B + HRRZS B + IMULI B,177. + ADD A,B + MOVEM C,IMAGE(A) + POP P,B + POP P,A + POPJ P, + +;Draw a horizontal line, length and x in A, y in B. +XLINE: PUSH P,B + HRRZS B + IMULI B,177. + ADD A,B + MOVEM C,IMAGE(A) + AOBJN A,.-1 + POP P,B + POPJ P, + +;Draw a vertical line, length and x in A, y in B. +YLINE: PUSH P,B + HRRZS B + IMULI B,177. + ADD A,B + MOVEM C,IMAGE(A) + ADDI A,176. + AOBJN A,.-2 + POP P,B + POPJ P, + +;Draw alignment patterns, A points to coordinates. +ALIGN: MOVE D,VERSION + IDIVI D,7 + ADDI D,2 + MOVNS D + HRL E,D + HRR E,A + HRLS D + HRR D,A + PUSH P,D + ADD D,[2,,1] + TLNN D,-1 + JRST ALIGN3 + JRST ALIGN2 + +ALIGN1: MOVE D,(P) + HLRZ F,E + CAIN F,-1 + ADD D,[1,,1] +ALIGN2: MOVE A,(D) + HRLI A,-5 + MOVE B,(E) + HRLI B,-5 + PUSHJ P,BOX + AOBJN D,ALIGN2 +ALIGN3: AOBJN E,ALIGN1 + POP P, + POPJ P, + +PAINT: .IOT TYOC,[^P] ;Move cursor to bottom line. + .IOT TYOC,["Z] + .IOT TYOC,[^P] ;Move up and to the left, + .IOT TYOC,["U] ;away from the QR code. + .IOT TYOC,[^P] + .IOT TYOC,["H] + .IOT TYOC,[80.+8] + ;It would be nice to send ^P C to clear the screen, + ;but this is done asynchronously in the TV-11, so it + ;will clobber the graphics we draw in the buffer. + + MOVE A,[-10,,TVPAG] ;Map in TV frame buffer. + MOVEI B,0 + .CALL [ SETZ + 'CORBLK + MOVEI %CBWRT + MOVEI %JSELF + MOVE A + MOVEI %JSTVB + SETZ B ] + JRST NOTV + + .SUSET [.RTVCREG,,A] ;Set TV ALU to MOVEM mode. + MOVEI B,17 + DPB B,[341000,,A] + .SUSET [.STVCREG,,A] + SETZ TVBUF ;Clear frame buffer. + MOVE B,[TVBUF,,TVBUF+1] + BLT B,TVBUF+<10*2000>-1 + + MOVEI B,16 ;Set ALU to IOR mode. + DPB B,[341000,,A] + .SUSET [.STVCREG,,A] + + MOVN B,SIZE + HRLZS B +YLOOP: MOVN A,SIZE + HRLZS A +XLOOP: PUSHJ P,MODULE + PUSHJ P,SQUARE + AOBJN A,XLOOP + AOBJN B,YLOOP + POPJ P, + +MODULE: PUSH P,A + PUSH P,B + HRRZS A + HRRZS B + IMULI B,177. + ADD A,B + SKIPL IMAGE(A) + AOS -2(P) + POP P,B + POP P,A + POPJ P, + +NOTV: .VALUE [ASCIZ /:Must run on a TV. + +:KILLî/] + +MODE: %MDNUM ;Data mode. +VERSION:1 ;Symbol version. +MASK: 0 ;Data mask. +LEVEL: 1 ;Error correction level. +SCALE: 7 ;Module size. +MARGIN: 50. ;Offset from display upper and left edge. + +;Draw a square on TV, x-y coordinates in A and B. +SQUARE: PUSH P,A + PUSH P,B + PUSH P,C + PUSH P,D + PUSH P,E + HRRZS A + IMUL A,SCALE + ADD A,MARGIN + IMUL B,SCALE + ADD B,MARGIN + IMULI B,22 + MOVEI C,TVBUF(B) + IDIVI A,32. + ADD C,A + MOVE D,PIXELS + MOVEI E,0 + MOVNS B + ROTC D,-4(B) + LSH D,4 + MOVE B,SCALE +SQUAR1: MOVEM D,(C) + MOVEM E,1(C) + ADDI C,22 + SOJG B,SQUAR1 + POP P,E + POP P,D + POP P,C + POP P,B + POP P,A + POPJ P, + +;Store data in A, number of bits in B. +STORE: JUMPE B,CPOPJ + PUSH P,C + PUSH P,D + MOVE C,B + LSH C,30. + TLO C,100 ;1-bit byte pointer + HRRI C,A +STORE1: ILDB D,C + IDPB D,PTR + SOJG B,STORE1 + POP P,D + POP P,C + POPJ P, + +;Store numeric from asciz, byte pointer in A. +STNUM: MOVE D,LENGTH +STNUM1: SOJL D,CPOPJ + ILDB C,A + SUBI C,"0 + SOJL D,[MOVEI B,4 ? JRST STNUM2] + ILDB B,A + IMULI C,10. + ADDI C,-"0(B) + SOJL D,[MOVEI B,7 ? JRST STNUM2] + ILDB B,A + IMULI C,10. + ADDI C,-"0(B) + MOVEI B,10. + MOVE A,C + PUSHJ P,STORE + JRST STNUM1 +STNUM2: MOVE A,C + PUSHJ P,STORE +CPOPJ: POPJ P, + +;Store alphanumeric from ASCII, byte pointer in A. +STANUM: MOVE D,LENGTH +STANU1: SOJL D,CPOPJ + ILDB B,A + PUSHJ P,ANUM + .VALUE ;Bug if this happens. + SOJL D,STANU2 + ILDB B,A + IMULI C,45. + PUSH P,C + PUSHJ P,ANUM + .VALUE + ADDM C,(P) + EXCH A,(P) + MOVEI B,11. + PUSHJ P,STORE + POP P,A + JRST STANU1 +STANU2: MOVE A,C + MOVEI B,6 + PUSHJ P,STORE + POPJ P, + +ANUM: MOVSI C,-ANTABL ;Get alphanumeric code. + CAME B,ANTAB(C) + AOBJN C,.-1 + SKIPGE C + AOS (P) ;Skip return when found. + POPJ P, + +ANTAB: "0 ? "1 ? "2 ? "3 ? "4 ? "5 ? "6 ? "7 ? "8 ? "9 + "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 + " ? "$ ? "% ? "* ? "+ ? "- ? ". ? "/ ? ": +ANTABL=.-ANTAB + +;Store 8-bit bytes, byte pointer in A. +STBYTE: MOVE D,A + MOVE C,LENGTH +STBYT1: SOJL C,CPOPJ + ILDB A,D + MOVEI B,8. + PUSHJ P,STORE + JRST STBYT1 + +;Length bits. +LTAB: 0 +REPEAT 9,[LTAB0(C) ;Version 1 - 9 +] +REPEAT 17.,[LTAB1(C) ;Version 10 - 26 +] +REPEAT 15.,[LTAB2(C) ;Version 27 - 40 +] +LTAB0: 0 ? 10. ? 9 ? 0 ? 8 ? 0 ? 0 ? 0 ? 8 + 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 +LTAB1: 0 ? 12. ? 11. ? 0 ? 16. ? 0 ? 0 ? 0 ? 10. + 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 +LTAB2: 0 ? 14. ? 13. ? 0 ? 16. ? 0 ? 0 ? 0 ? 12. + 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 + +STAB: +LOC STAB+%MDNUM + STNUM +LOC STAB+%MDANUM + STANUM +LOC STAB+%MDBYTE + STBYTE +LOC STAB+20 + +CTAB: +LOC CTAB+%MDNUM + [ IMULI B,10. ? ADDI B,2 ? IDIVI B,3 ? POPJ P, ] +LOC CTAB+%MDANUM + [ IMULI B,11. ? ADDI B,1 ? IDIVI B,2 ? POPJ P, ] +LOC CTAB+%MDBYTE + [ IMULI B,8 ? POPJ P, ] +LOC CTAB+20 + +FTAB: FTABM(B) ;Medium. + FTABL(B) ;Low. + FTABH(B) ;High. + FTABQ(B) ;Quartile. + +FTABM: 52022 ? 50445 ? 57174 ? 55513 ? 42771 ? 40316 ? 47627 ? 45240 +FTABL: 73704 ? 71363 ? 76652 ? 74235 ? 63057 ? 61430 ? 66101 ? 64566 +FTABH: 13211 ? 11676 ? 16347 ? 14720 ? 03542 ? 01125 ? 06414 ? 04073 +FTABQ: 32537 ? 30150 ? 37461 ? 35006 ? 22264 ? 20603 ? 27332 ? 25755 + +VTAB: 0 ? 0 ? 0 ? 0 ? 0 ? 0 ? 0 + 076224 ? 102674 ? 115231 ? 122323 ? 135766 ? 143542 ? 154107 + 163015 ? 174450 ? 205570 ? 212135 ? 225027 ? 232462 ? 244646 + 253203 ? 264311 ? 273754 ? 307304 ? 310741 ? 327653 ? 330216 + 346032 ? 351477 ? 366565 ? 371120 ? 404725 ? 413360 ? 424272 + 433637 ? 445413 ? 452056 ? 465144 ? 472501 ? 506151 + +ATAB: 0 ? 0 ? ATAB2 ? ATAB3 ? ATAB4 ? ATAB5 ? ATAB6 ? ATAB7 + ATAB8 ? ATAB9 ? ATAB10 ? ATAB11 ? ATAB12 ? ATAB13 ? ATAB14 + ATAB15 ? ATAB16 ? ATAB17 ? ATAB18 ? ATAB19 ? ATAB20 ? ATAB21 + ATAB22 ? ATAB23 ? ATAB24 ? ATAB25 ? ATAB26 ? ATAB27 ? ATAB28 + ATAB29 ? ATAB30 ? ATAB31 ? ATAB32 ? ATAB33 ? ATAB34 ? ATAB35 + ATAB36 ? ATAB37 ? ATAB38 ? ATAB39 ? ATAB40 + +ATAB2: 4 ? 16. +ATAB3: 4 ? 20. +ATAB4: 4 ? 24. +ATAB5: 4 ? 28. +ATAB6: 4 ? 32. +ATAB7: 4 ? 20. ? 36. +ATAB8: 4 ? 22. ? 40. +ATAB9: 4 ? 24. ? 44. +ATAB10: 4 ? 26. ? 48. +ATAB11: 4 ? 28. ? 52. +ATAB12: 4 ? 30. ? 56. +ATAB13: 4 ? 32. ? 60. +ATAB14: 4 ? 24. ? 44. ? 64. +ATAB15: 4 ? 24. ? 46. ? 68. +ATAB16: 4 ? 24. ? 48. ? 72. +ATAB17: 4 ? 28. ? 52. ? 76. +ATAB18: 4 ? 28. ? 54. ? 80. +ATAB19: 4 ? 28. ? 56. ? 84. +ATAB20: 4 ? 32. ? 60. ? 88. +ATAB21: 4 ? 26. ? 48. ? 70. ? 92. +ATAB22: 4 ? 24. ? 48. ? 72. ? 96. +ATAB23: 4 ? 28. ? 52. ? 76. ? 100. +ATAB24: 4 ? 26. ? 52. ? 78. ? 104. +ATAB25: 4 ? 30. ? 56. ? 82. ? 108. +ATAB26: 4 ? 28. ? 56. ? 84. ? 112. +ATAB27: 4 ? 32. ? 60. ? 88. ? 116. +ATAB28: 4 ? 24. ? 48. ? 72. ? 96. ? 120. +ATAB29: 4 ? 28. ? 52. ? 76. ? 100. ? 124. +ATAB30: 4 ? 24. ? 50. ? 76. ? 102. ? 128. +ATAB31: 4 ? 28. ? 54. ? 80. ? 106. ? 132. +ATAB32: 4 ? 32. ? 48. ? 84. ? 110. ? 136. +ATAB33: 4 ? 28. ? 56. ? 84. ? 112. ? 140. +ATAB34: 4 ? 32. ? 60. ? 88. ? 116. ? 144. +ATAB35: 4 ? 28. ? 52. ? 76. ? 100. ? 124. ? 148. +ATAB36: 4 ? 22. ? 48. ? 74. ? 100. ? 126. ? 152. +ATAB37: 4 ? 26. ? 52. ? 78. ? 104. ? 130. ? 156. +ATAB38: 4 ? 30. ? 56. ? 82. ? 108. ? 134. ? 160. +ATAB39: 4 ? 24. ? 52. ? 80. ? 108. ? 136. ? 164. +ATAB40: 4 ? 28. ? 56. ? 84. ? 112. ? 140. ? 168. + +;Number of blocks. +BTAB: BTABM(C) ;Medium. + BTABL(C) ;Low. + BTABH(C) ;High. + BTABQ(C) ;Quartile. + +BTABM: 0 ? 1 ? 1 ? 1 ? 2 ? 2 ? 4 ? 4 ? 4 ? 5 ? 5 ? 5 ? 8 + 9 ? 9 ? 10. ? 10. ? 11. ? 13. ? 14. ? 16. ? 17. + 17. ? 18. ? 20. ? 21. ? 23. ? 25. ? 26. ? 28. ? 29. + 31. ? 33. ? 35. ? 37. ? 38. ? 40. ? 43. ? 45. ? 47. ? 49. +BTABL: 0 ? 1 ? 1 ? 1 ? 1 ? 1 ? 2 ? 2 ? 2 ? 2 ? 4. ? 4. ? 4 + 4 ? 4 ? 6 ? 6 ? 6 ? 6 ? 7 ? 8 ? 8 ? 9 ? 9 + 10. ? 12. ? 12. ? 12. ? 13. ? 14. ? 15. ? 16. ? 17. + 18. ? 19. ? 19. ? 20. ? 21. ? 22. ? 24. ? 25. +BTABH: 0 ? 1 ? 1 ? 2 ? 4 ? 4 ? 4 ? 5 ? 6 ? 8 ? 8 ? 11. + 11. ? 16. ? 16. ? 18. ? 16. ? 19. ? 21. ? 25. ? 25. + 25. ? 34. ? 30. ? 32. ? 35. ? 37. ? 40. ? 42. ? 45. + 48. ? 51. ? 54. ? 57. ? 60. ? 63. ? 66. ? 70. ? 74. + 77. ? 81. +BTABQ: 0 ? 1 ? 1 ? 2 ? 2 ? 4 ? 4 ? 6 ? 6 ? 8 ? 8 ? 8 ? 10. + 12. ? 16. ? 12. ? 17. ? 16. ? 18. ? 21. ? 20. ? 23. + 23. ? 25. ? 27. ? 29. ? 34. ? 34. ? 35. ? 38. ? 40. + 43. ? 45. ? 48. ? 51. ? 53. ? 56. ? 59. ? 62. ? 65. ? 68. + +;Number of ECC bytes per block. +ETAB: ETABM(C) ;Medium. + ETABL(C) ;Low. + ETABH(C) ;High. + ETABQ(C) ;Quartile. + +ETABM: 0 ? 10. ? 16. ? 26. ? 18. ? 24. ? 16. ? 18. ? 22. + 22. ? 26. ? 30. ? 22. ? 22. ? 24. ? 24. ? 28. ? 28. + 26. ? 26. ? 26. ? 26. ? 28. ? 28. ? 28. ? 28. ? 28. + 28. ? 28. ? 28. ? 28. ? 28. ? 28. ? 28. ? 28. ? 28. + 28. ? 28. ? 28. ? 28. ? 28. +ETABL: 0 ? 7 ? 10. ? 15. ? 20. ? 26. ? 18. ? 20. ? 24. + 30. ? 18. ? 20. ? 24. ? 26. ? 30. ? 22. ? 24. ? 28. + 30. ? 28. ? 28. ? 28. ? 28. ? 30. ? 30. ? 26. ? 28. + 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. + 30. ? 30. ? 30. ? 30. ? 30. +ETABH: 0 ? 17. ? 28. ? 22. ? 16. ? 22. ? 28. ? 26. ? 26. + 24. ? 28. ? 24. ? 28. ? 22. ? 24. ? 24. ? 30. ? 28. + 28. ? 26. ? 28. ? 30. ? 24. ? 30. ? 30. ? 30. ? 30. + 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. + 30. ? 30. ? 30. ? 30. ? 30. +ETABQ: 0 ? 13. ? 22. ? 18. ? 26. ? 18. ? 24. ? 18. ? 22. + 20. ? 24. ? 28. ? 26. ? 24. ? 20. ? 30. ? 24. ? 28. + 28. ? 26. ? 30. ? 28. ? 30. ? 30. ? 30. ? 30. ? 28. + 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. ? 30. + 30. ? 30. ? 30. ? 30. ? 30. + +MESSAGE:BLOCK 7100. ;Maximum amount of data. +MAX=<.-MESSAGE>*7 +PDL: BLOCK 100 + +IMAGE: BLOCK <177.*177.> ;One word per module. + +TVPAG=<.+1777>/2000 +TVBUF=TVPAG_10. ;TV frame buffer bitmap. +LOC TVBUF+10*2000 + +DATA: BLOCK 24000./36. ;Encoded data. +EDAT=.-1 +OUTPUT: BLOCK 30000./36. ;Interleaved data with error correcting codes. +EOUT=.-1 +ECC: BLOCK 2500. +DIVISOR:BLOCK 30. + +END GO