From d150cbc5af0b119ed48a979b53613fc9cce916d1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 12 Apr 2021 16:33:25 +0200 Subject: [PATCH] added option to generate RS polynomial on-the-fly --- QRCodeGen.inc | 159 +++++++++++++++++++++++++++++++++------------- QRCodeGenDemo.asm | 13 ++-- 2 files changed, 125 insertions(+), 47 deletions(-) diff --git a/QRCodeGen.inc b/QRCodeGen.inc index bbc03d7..2fddd37 100644 --- a/QRCodeGen.inc +++ b/QRCodeGen.inc @@ -78,49 +78,6 @@ QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44 ; The following code has been partially converted from the C code of the ; QR code generator found at https://github.com/nayuki/QR-Code-generator -;----------------------------------------------------------- - MAC _RS_REMAINDER -;----------------------------------------------------------- -.i = tmpVars+2 -.factor = tmpVars+3 - -; memset(result, 0, 16); // done in START_TEXT -; for (int i = dataLen-1; i >= 0; i--) { // Polynomial division - ldx #QR_MAX_DATA-1 -.loopI - stx .i -; uint8_t factor = data[i] ^ result[degree - 1]; - lda msgData,x - eor remainder + QR_DEGREE - 1 - sta .factor -; memmove(&result[1], &result[0], (size_t)(16 - 1) * sizeof(result[0])); - ldx #QR_DEGREE-1 -.loopMove - lda remainder-1,x - sta remainder,x - dex - bne .loopMove -; result[0] = 0; - lda #0 - sta remainder -; for (int j = 16-1; j >= 0; j--) - ldx #QR_DEGREE-1 -.loopJ -; result[j] ^= reedSolomonMultiply(generator[j], factor); - lda Generator,x - ldy .factor - _RS_MULT - eor remainder,x - sta remainder,x -; } - dex - bpl .loopJ -; } - ldx .i - dex - bpl .loopI - ENDM - ;----------------------------------------------------------- ; Returns the product of the two given field elements modulo GF(2^8/0x11D). ; All inputs are valid. @@ -154,6 +111,114 @@ QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44 bpl .loopI ENDM + IF QR_GENERATE +; Computes a Reed-Solomon ECC generator polynomial for degree 16, storing in result[0 : 16-1]. +; This is implemented as a lookup table too (Generator) +;----------------------------------------------------------- + MAC _RS_DIVISOR +;----------------------------------------------------------- +; E.g. g(x)=(x+1)(x+?)(x+?^2)(x+?^3)...(x+?^15) +; = x^16+3Bx^15+0Dx^14+68x^13+BDx^12+44x^11+d1x^10+1e^x9+08x^8 +; +A3x^7+41x^6+29x^5+E5x^4+62x^3+32x^2+24x+3B +.root = tmpVars+2 +.i = tmpVars+3 + +; memset(qrGenerator, 1, 16); + ldx #QR_DEGREE-1 + stx .i + ldy #0 +.loopClear + sty qrGenerator,x + dex + bne .loopClear +; qrGenerator[0] = 1; // Start off with the monomial x^0 + iny + sty qrGenerator +; uint8_t root = 1; + sty .root +; for (int i = 0; i < degree; i++) { +.loopI +; // Multiply the current product by (x - r^i) +; for (int j = degree-1; j >= 0; j--) { + ldx #QR_DEGREE-1 +.loopJ +; qrGenerator[j] = reedSolomonMultiply(qrGenerator[j], root); + lda qrGenerator,x + ldy .root + jsr RSMult +; if (j) + dex + bmi .skipEor +; qrGenerator[j] ^= qrGenerator[j - 1]; + eor qrGenerator,x +.skipEor + sta qrGenerator+1,x + txa + bpl .loopJ +; root = reedSolomonMultiply(root, 0x02); + lda .root + ldy #$02 + jsr RSMult + sta .root + dec .i + bpl .loopI + ENDM + +;----------------------------------------------------------- +RSMult SUBROUTINE + _RS_MULT + rts +;----------------------------------------------------------- + ENDIF ; /QR_GENERATE + +;----------------------------------------------------------- + MAC _RS_REMAINDER +;----------------------------------------------------------- +.i = tmpVars+2 +.factor = tmpVars+3 + +; memset(result, 0, 16); // done in START_TEXT +; for (int i = dataLen-1; i >= 0; i--) { // Polynomial division + ldx #QR_MAX_DATA-1 +.loopI + stx .i +; uint8_t factor = data[i] ^ result[degree - 1]; + lda msgData,x + eor remainder + QR_DEGREE - 1 + sta .factor +; memmove(&result[1], &result[0], (size_t)(16 - 1) * sizeof(result[0])); + ldx #QR_DEGREE-1 +.loopMove + lda remainder-1,x + sta remainder,x + dex + bne .loopMove +; result[0] = 0; + lda #0 + sta remainder +; for (int j = 16-1; j >= 0; j--) + ldx #QR_DEGREE-1 +.loopJ +; result[j] ^= reedSolomonMultiply(generator[j], factor); + ldy .factor + IF QR_GENERATE + lda qrGenerator,x + jsr RSMult + ELSE + lda Generator,x + _RS_MULT + ENDIF + eor remainder,x + sta remainder,x +; } + dex + bpl .loopJ +; } + ldx .i + dex + bpl .loopI + ENDM + ;----------------------------------------------------------- ; Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of ; the QR Code to be black at function modules and white at codeword modules (including unused remainder bits). @@ -546,6 +611,11 @@ QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44 ; This is the main macro to use! QRCodeCode + IF QR_GENERATE +; generate the Reed-Solomon ECC generator polynomial +RSDevisor + _RS_DIVISOR + ENDIF ; calculate the ECC RSRemainder _RS_REMAINDER @@ -677,6 +747,7 @@ FormatX2 BitMask .byte $80, $40, $20, $10, $8, $4, $2, $1 + IF QR_GENERATE = 0 Generator ; data in reversed order! IF QR_DEGREE = 7 .byte $75, $44, $0b, $a4, $9a, $7a, $7f @@ -726,6 +797,8 @@ Generator ; data in reversed order! QR_DEGREE = . - Generator ; verify data size + ENDIF ; /QR_GENERATE + ECHO "QR Code encoding data:", [. - QRCodeData]d, "bytes" _QR_TOTAL SET _QR_TOTAL + . - QRCodeData diff --git a/QRCodeGenDemo.asm b/QRCodeGenDemo.asm index a6955f1..efad621 100644 --- a/QRCodeGenDemo.asm +++ b/QRCodeGenDemo.asm @@ -39,11 +39,13 @@ NTSC = 1 ; 0 = PAL50 ; QR Code Generator Switches QR_VERSION = 2 ; 1, 2 or 3 (TODO 1 and 3) QR_LEVEL = 1 ; 0 (L), 1 (M), 2 (Q) and 3 (H)) -QR_PADDING = 1 ; (+22) add padding bytes +QR_PADDING = 1 ; (+22 bytes) add padding bytes (optional) +QR_GENERATE = 1 ; (+~12 bytes) generates Reed-Solomon ECC generator polynomial on-the-fly + ; else uses built-in table ; Atari 2600 specific QR settings (set to 0 for other platforms) QR_OVERLAP = 1 ; overlaps input and output data to save RAM (defined for version 2 only!) -QR_SINGLE_MASK = 0 ; (-255) if 1 uses only 1 of the 8 mask pattern +QR_SINGLE_MASK = 0 ; (-255 bytes) if 1 uses only 1 of the 8 mask pattern IF QR_VERSION = 1 || QR_VERSION = 3 ECHO "" @@ -97,6 +99,9 @@ firstMsl = qrCodeLst + QR_SIZE * 1 grp1Lst = qrCodeLst + NUM_FIRST + QR_SIZE * 1 grp0RLst = qrCodeLst + NUM_FIRST + QR_SIZE * 2 CODE_LST_SIZE = . - qrCodeLst + IF QR_GENERATE +qrGenerator ds QR_DEGREE + ENDIF ;--------------------------------------- ; QR code total = 89/127 bytes @@ -218,8 +223,6 @@ CODE_LST_SIZE = . - qrCodeLst ENDIF ENDM - include QRCodeGen.inc - ;=============================================================================== ; R O M - C O D E @@ -308,6 +311,8 @@ DrawScreen SUBROUTINE rts ; DrawScreen + include QRCodeGen.inc + ;--------------------------------------------------------------- Start SUBROUTINE ;---------------------------------------------------------------