added instructions.txt

refined constants and variables
This commit is contained in:
thrust26 2021-04-15 16:23:50 +02:00
parent d387dcc095
commit 8c04c30b55
3 changed files with 137 additions and 80 deletions

View File

@ -1,8 +1,26 @@
;=============================================================================== ;===============================================================================
; Q R C O D E C O N S T A N T S ; U S E R - D E F I N E D Q R C O D E C O N S T A N T S
;=============================================================================== ;===============================================================================
; Do NOT change these constants! IFNCONST QR_VERSION
QR_VERSION = 2 ; 1..3, QR code size (21, 25, 29)
ENDIF
IFNCONST QR_LEVEL
QR_LEVEL = 0 ; 0..4, error correction levels L, M, Q, H
ENDIF
IFNCONST QR_PADDING
QR_PADDING = 1 ; 0|1, add padding bytes add the end of test message text
ENDIF
IFNCONST QR_GENERATE
QR_GENERATE = 0 ; 0|1, generate Reed-Solomon ECC generator polynomial on-the-fly
ENDIF
;===============================================================================
; C A L C U L A T E D Q R C O D E C O N S T A N T S
;===============================================================================
; Do NOT change the following constants!
IFNCONST QR_OVERLAP IFNCONST QR_OVERLAP
QR_OVERLAP = 0 QR_OVERLAP = 0
@ -14,8 +32,7 @@ QR_SINGLE_MASK = 0
QR_DIRECT_DRAW = 0 QR_DIRECT_DRAW = 0
ENDIF ENDIF
IF QR_VERSION = 1 ;{ IF QR_VERSION = 1 ; 21x21 QR code
; 21x21 QR code
IF QR_LEVEL = 0 IF QR_LEVEL = 0
QR_DEGREE = 7 ; for version 1, level L QR codes QR_DEGREE = 7 ; for version 1, level L QR codes
ENDIF ENDIF
@ -28,10 +45,9 @@ QR_DEGREE = 13 ; for version 1, level Q QR codes
IF QR_LEVEL = 3 IF QR_LEVEL = 3
QR_DEGREE = 17 ; for version 1, level H QR codes QR_DEGREE = 17 ; for version 1, level H QR codes
ENDIF ENDIF
ENDIF ;} ENDIF
IF QR_VERSION = 2 IF QR_VERSION = 2 ; 25x25 QR code
; 25x25 QR code
IF QR_LEVEL = 0 IF QR_LEVEL = 0
QR_DEGREE = 10 ; for version 2, level L QR codes QR_DEGREE = 10 ; for version 2, level L QR codes
ENDIF ENDIF
@ -46,8 +62,7 @@ QR_DEGREE = 28 ; for version 2, level H QR codes
ENDIF ENDIF
ENDIF ENDIF
IF QR_VERSION = 3 ;{ IF QR_VERSION = 3 ; 29x29 QR code
; 29x29 QR code
IF QR_LEVEL = 0 IF QR_LEVEL = 0
QR_DEGREE = 15 ; for version 3, level L QR codes QR_DEGREE = 15 ; for version 3, level L QR codes
ENDIF ENDIF
@ -59,7 +74,7 @@ QR_DEGREE = 26 ; for version 3, level M QR codes
ECHO "ERROR: Version 3, Level", [QR_LEVEL]d, "not supported" ECHO "ERROR: Version 3, Level", [QR_LEVEL]d, "not supported"
ERR ERR
ENDIF ENDIF
ENDIF ;} ENDIF
QR_SIZE = 17 + QR_VERSION * 4 QR_SIZE = 17 + QR_VERSION * 4
@ -82,7 +97,16 @@ QR_POLY = $11d ; GF(2^8) is based on 9 bit polynomial
QR_FORMATS = 15 ; 15 type information bits QR_FORMATS = 15 ; 15 type information bits
QR_MAX_MSG = QR_MAX_DATA - 2 QR_MAX_MSG = QR_MAX_DATA - 2
QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44 QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; e.g. 44
;===============================================================================
; V A R I A B L E S
;===============================================================================
qrRemainder = qrData ; (QR_DEGREE = e.g. 16 bytes)
qrMsgData = qrData + QR_DEGREE ; (QR_MAX_DATA = e.g. 28 bytes)
qrMsgIdx = qrTmpVars + 3
;=============================================================================== ;===============================================================================
@ -100,8 +124,8 @@ QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44
; Russian peasant multiplication (x * y) ; Russian peasant multiplication (x * y)
; Input: A = x, Y = y ; Input: A = x, Y = y
; Result: A ; Result: A
.x = tmpVars .x = qrTmpVars
.y = tmpVars+1 .y = qrTmpVars+1
sta .x sta .x
sty .y sty .y
@ -134,8 +158,8 @@ QR_TOTAL = QR_MAX_DATA + QR_DEGREE ; 44
; E.g. g(x)=(x+1)(x+?)(x+?^2)(x+?^3)...(x+?^15) ; 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 ; = 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 ; +A3x^7+41x^6+29x^5+E5x^4+62x^3+32x^2+24x+3B
.root = tmpVars+2 .root = qrTmpVars+2
.i = tmpVars+3 .i = qrTmpVars+3
; memset(qrGenerator, 1, 16); ; memset(qrGenerator, 1, 16);
ldx #QR_DEGREE-1 ldx #QR_DEGREE-1
@ -188,32 +212,32 @@ RSMult SUBROUTINE
;----------------------------------------------------------- ;-----------------------------------------------------------
MAC _RS_REMAINDER MAC _RS_REMAINDER
;----------------------------------------------------------- ;-----------------------------------------------------------
.i = tmpVars+2 .i = qrTmpVars+2
.factor = tmpVars+3 .factor = qrTmpVars+3
; memset(result, 0, 16); // done in START_TEXT ; memset(result, 0, 16); // done in START_TEXT
; for (int i = dataLen-1; i >= 0; i--) { // Polynomial division ; for (int i = dataLen-1; i >= 0; i--) { // Polynomial division
ldx #QR_MAX_DATA-1 ldx #QR_MAX_DATA-1
.loopI .loopI
stx .i stx .i
; uint8_t factor = data[i] ^ result[degree - 1]; ; uint8_t factor = qrMsgData[i] ^ qrRemainder[degree - 1];
lda msgData,x lda qrMsgData,x
eor remainder + QR_DEGREE - 1 eor qrRemainder + QR_DEGREE - 1
sta .factor sta .factor
; memmove(&result[1], &result[0], (size_t)(16 - 1) * sizeof(result[0])); ; memmove(&qrRemainder[1], &qrRemainder[0], (size_t)(16 - 1) * sizeof(qrRemainder[0]));
ldx #QR_DEGREE-1 ldx #QR_DEGREE-1
.loopMove .loopMove
lda remainder-1,x lda qrRemainder-1,x
sta remainder,x sta qrRemainder,x
dex dex
bne .loopMove bne .loopMove
; result[0] = 0; ; qrRemainder[0] = 0;
lda #0 lda #0
sta remainder sta qrRemainder
; for (int j = 16-1; j >= 0; j--) ; for (int j = 16-1; j >= 0; j--)
ldx #QR_DEGREE-1 ldx #QR_DEGREE-1
.loopJ .loopJ
; result[j] ^= reedSolomonMultiply(generator[j], factor); ; qrRemainder[j] ^= reedSolomonMultiply(generator[j], factor);
ldy .factor ldy .factor
IF QR_GENERATE IF QR_GENERATE
lda qrGenerator,x lda qrGenerator,x
@ -222,8 +246,8 @@ RSMult SUBROUTINE
lda Generator,x lda Generator,x
_RS_MULT _RS_MULT
ENDIF ENDIF
eor remainder,x eor qrRemainder,x
sta remainder,x sta qrRemainder,x
; } ; }
dex dex
bpl .loopJ bpl .loopJ
@ -293,12 +317,12 @@ BlackFunc SUBROUTINE
DrawPattern SUBROUTINE DrawPattern SUBROUTINE
;--------------------------------------------------------------- ;---------------------------------------------------------------
; Y = index, A = fill ; Y = index, A = fill
.index = tmpVars .index = qrTmpVars
.width = tmpVars+1 .width = qrTmpVars+1
.height = tmpVars+2 .height = qrTmpVars+2
.offset = tmpVars+3 .offset = qrTmpVars+3
.tmpPat = tmpVars+4 .tmpPat = qrTmpVars+4
.fill = tmpVars+5 .fill = qrTmpVars+5
sty .index sty .index
sta .fill sta .fill
@ -328,10 +352,10 @@ DrawPattern SUBROUTINE
.invert .invert
jsr InvertPixel jsr InvertPixel
.skipInvert .skipInvert
iny iny ; x++
dec .width dec .width
bne .loopBit bne .loopBit
dex dex ; y--
ldy .offset ldy .offset
iny iny
dec .height dec .height
@ -353,18 +377,18 @@ DrawPattern SUBROUTINE
MAC _DRAW_CODEWORDS MAC _DRAW_CODEWORDS
;----------------------------------------------------------- ;-----------------------------------------------------------
; Note: This part has the maximum RAM usage ; Note: This part has the maximum RAM usage
.vert = tmpVars+0 .vert = qrTmpVars+0
.j = tmpVars+1 .j = qrTmpVars+1
.y = tmpVars+2 .y = qrTmpVars+2
IF QR_DIRECT_DRAW IF QR_DIRECT_DRAW
.iBit = tmpVars+3 .iBit = qrTmpVars+3
.iByte = tmpVars+4 .iByte = qrTmpVars+4
.right1 = tmpVars+5 .right1 = qrTmpVars+5
ELSE ELSE
; must not overlap with DrawPattern space ; must not overlap with DrawPattern space
.iBit = tmpVars+6 .iBit = qrTmpVars+6
.iByte = tmpVars+7 .iByte = qrTmpVars+7
.right1 = tmpVars+8 .right1 = qrTmpVars+8
ENDIF ENDIF
; blacken the (right) function modules in the bitmap ; blacken the (right) function modules in the bitmap
@ -441,9 +465,9 @@ DrawPattern SUBROUTINE
ldx .y ldx .y
jsr CheckPixel jsr CheckPixel
bne .skipPixel bne .skipPixel
; bool black = getBit(data[i >> 3], 7 - (i & 7)); ; bool black = getBit(qrData[i >> 3], 7 - (i & 7));
ldx .iByte ldx .iByte
lda data,x lda qrData,x
ldx .iBit ldx .iBit
and BitMask,x and BitMask,x
beq .skipInv beq .skipInv
@ -485,7 +509,7 @@ DrawPattern SUBROUTINE
MAC _APPLY_MASK MAC _APPLY_MASK
;----------------------------------------------------------- ;-----------------------------------------------------------
IF QR_SINGLE_MASK IF QR_SINGLE_MASK
.y = tmpVars .y = qrTmpVars
ldx #QR_SIZE - 1 ldx #QR_SIZE - 1
.loopY .loopY
stx .y stx .y
@ -503,12 +527,12 @@ DrawPattern SUBROUTINE
dex dex
bpl .loopY bpl .loopY
ELSE ELSE
.y = tmpVars .y = qrTmpVars
;.x = tmpVars+2 ;.x = qrTmpVars+2
.xMod3 = tmpVars+1 .xMod3 = qrTmpVars+1
.yMod3 = tmpVars+2 .yMod3 = qrTmpVars+2
.xDiv3 = tmpVars+3 .xDiv3 = qrTmpVars+3
.tmp = tmpVars+4 .tmp = qrTmpVars+4
lda #0 lda #0
sta .yMod3 sta .yMod3
@ -641,7 +665,7 @@ DrawPattern SUBROUTINE
MAC _DRAW_FORMAT MAC _DRAW_FORMAT
;----------------------------------------------------------- ;-----------------------------------------------------------
IF QR_SINGLE_MASK = 0 || QR_DIRECT_DRAW = 0 IF QR_SINGLE_MASK = 0 || QR_DIRECT_DRAW = 0
.idx = tmpVars .idx = qrTmpVars
ldy #QR_FORMATS-1 ldy #QR_FORMATS-1
.loopFormat .loopFormat
@ -689,21 +713,21 @@ DrawPattern SUBROUTINE
lsr lsr
ora #(QR_MODE << 4) ora #(QR_MODE << 4)
; (QR_MODE << 4) | (MSG_LEN >> 4) ; (QR_MODE << 4) | (MSG_LEN >> 4)
sta msgData + QR_MAX_DATA - 1 sta qrMsgData + QR_MAX_DATA - 1
txa txa
asl asl
asl asl
asl asl
asl asl
; (MSG_LEN << 4) ; (MSG_LEN << 4)
sta msgData + QR_MAX_DATA - 2 sta qrMsgData + QR_MAX_DATA - 2
lda #QR_MAX_DATA - 3 lda #QR_MAX_DATA - 3
sta msgIdx sta qrMsgIdx
; clear the remaining data buffer ; clear the remaining data buffer
ldx #QR_TOTAL-3 ldx #QR_TOTAL-3
lda #0 lda #0
.loopClear .loopClear
sta data,x sta qrData,x
dex dex
bpl .loopClear bpl .loopClear
ENDM ENDM
@ -712,28 +736,28 @@ DrawPattern SUBROUTINE
MAC ADD_MSG_BYTE MAC ADD_MSG_BYTE
;--------------------------------------------------------------- ;---------------------------------------------------------------
; A = byte to add ; A = byte to add
ldx msgIdx ldx qrMsgIdx
pha pha
lsr lsr
lsr lsr
lsr lsr
lsr lsr
ora msgData + 1,x ora qrMsgData + 1,x
sta msgData + 1,x sta qrMsgData + 1,x
pla pla
asl asl
asl asl
asl asl
asl asl
sta msgData,x sta qrMsgData,x
dec msgIdx dec qrMsgIdx
ENDM ENDM
;----------------------------------------------------------- ;-----------------------------------------------------------
MAC STOP_MSG MAC STOP_MSG
;----------------------------------------------------------- ;-----------------------------------------------------------
IF QR_PADDING IF QR_PADDING
.msgLen = tmpVars .msgLen = qrTmpVars
; pad with optional filler bytes (QR code works without too) ; pad with optional filler bytes (QR code works without too)
lda #QR_MAX_MSG - 1 lda #QR_MAX_MSG - 1
sec sec
@ -742,11 +766,11 @@ DrawPattern SUBROUTINE
tax tax
.loopPadding .loopPadding
lda #$ec ; defined by QR standard lda #$ec ; defined by QR standard
sta msgData,x sta qrMsgData,x
dex dex
bmi .noPadding bmi .noPadding
lda #$11 ; defined by QR standard lda #$11 ; defined by QR standard
sta msgData,x sta qrMsgData,x
dex dex
bpl .loopPadding bpl .loopPadding
.noPadding .noPadding

View File

@ -88,19 +88,16 @@ random .byte
; QR code variables ; QR code variables
; all byte counts based on version 2, level M QR code ; all byte counts based on version 2, level M QR code
IF QR_DIRECT_DRAW IF QR_DIRECT_DRAW
tmpVars ds 6 qrTmpVars ds 6
ELSE ELSE
tmpVars ds 9 qrTmpVars ds 9
ENDIF ENDIF
msgIdx = tmpVars + 3
IF QR_SINGLE_MASK = 0 IF QR_SINGLE_MASK = 0
qrPattern .byte qrPattern .byte
ENDIF ENDIF
;--------------------------------------- ;---------------------------------------
data ds QR_TOTAL ; 44 bytes qrData ds QR_TOTAL ; 44 bytes
remainder = data ; (QR_DEGREE = 16 bytes)
msgData = data + QR_DEGREE ; (QR_MAX_DATA = 28 bytes)
;- - - - - - - - - - - - - - - - - - - - ;- - - - - - - - - - - - - - - - - - - -
; The QR code overlaps the data! It overwrites the data while being drawn. ; The QR code overlaps the data! It overwrites the data while being drawn.
IF QR_OVERLAP IF QR_OVERLAP
@ -109,7 +106,7 @@ QR_NON_OVER = 6
ELSE ELSE
QR_NON_OVER = 8 QR_NON_OVER = 8
ENDIF ENDIF
qrCodeLst = data + QR_NON_OVER ; all but 6/8 bytes overlap (version 2 only!) qrCodeLst = qrData + QR_NON_OVER ; all but 6/8 bytes overlap (version 2 only!)
ds NUM_FIRST + QR_SIZE*3 - QR_TOTAL + QR_NON_OVER ; 38/40 bytes ds NUM_FIRST + QR_SIZE*3 - QR_TOTAL + QR_NON_OVER ; 38/40 bytes
ELSE ELSE
qrCodeLst ds NUM_FIRST + QR_SIZE*3 ; 76 bytes qrCodeLst ds NUM_FIRST + QR_SIZE*3 ; 76 bytes
@ -120,7 +117,7 @@ grp1Lst = qrCodeLst + NUM_FIRST + QR_SIZE * 1
grp0RLst = qrCodeLst + NUM_FIRST + QR_SIZE * 2 grp0RLst = qrCodeLst + NUM_FIRST + QR_SIZE * 2
CODE_LST_SIZE = . - qrCodeLst CODE_LST_SIZE = . - qrCodeLst
IF QR_GENERATE IF QR_GENERATE
qrGenerator ds QR_DEGREE qrGenerator = . - QR_DEGREE
ENDIF ENDIF
;--------------------------------------- ;---------------------------------------
; QR code total = 89/127 bytes ; QR code total = 89/127 bytes
@ -333,7 +330,7 @@ DrawScreen SUBROUTINE
sta VBLANK sta VBLANK
stx TIM64T stx TIM64T
;--------------------------------------------------------------- ;---------------------------------------------------------------
.tmpFirst = tmpVars .tmpFirst = qrTmpVars
IF QR_SPRITE_GFX IF QR_SPRITE_GFX
BLOCK_H = 2 BLOCK_H = 2
@ -600,8 +597,8 @@ GenerateQR SUBROUTINE
MessageCode MessageCode
; convert the message into a data stream ; convert the message into a data stream
.msgLen = tmpVars .msgLen = qrTmpVars
.msgPtr = tmpVars+1 .msgPtr = qrTmpVars+1
lda random lda random
lsr lsr
lsr lsr
@ -639,7 +636,7 @@ _QR_TOTAL SET _QR_TOTAL + . - MessageCode
; |PF0 | PF1 | PF2 |PF0 | PF1 | PF2 | ; |PF0 | PF1 | PF2 |PF0 | PF1 | PF2 |
; | |7......0|0......7|4..7|7......0| | ; | |7......0|0......7|4..7|7......0| |
; |....|...XXXXX|XXXXXXXX|XXXX|XXXXXXXX|........| ; |....|...XXXXX|XXXXXXXX|XXXX|XXXXXXXX|........|
.tmpLeft = tmpVars .tmpLeft = qrTmpVars
ldx #QR_SIZE-1 ldx #QR_SIZE-1
.loopRows .loopRows
@ -857,7 +854,7 @@ Message14
Message15 Message15
.byte "1996 - Stella Emulator" .byte "1996 - Stella Emulator"
MessageEnd MessageEnd
; .byte "..the single hardest thing" ; .byte "the single hardest thing.."
MessagePtrLo MessagePtrLo
.byte <Message0, <Message1, <Message2, <Message3 .byte <Message0, <Message1, <Message2, <Message3

36
instructions.txt Normal file
View File

@ -0,0 +1,36 @@
6502 QR Code Generator - (C)2021 Thomas Jentzsch
Instructions:
1. Include QRCodeGen.inc into the code area of your own code
2. Define the following constants:
- QR_VERSION = 1..3 ; QR code size (21, 25, 29)
- QR_LEVEL = 0..3 ; error correction levels L, M, Q, H
- QR_PADDING = 0|1 ; add padding bytes add the end of test message text
- QR_GENERATE = 0|1 ; generate Reed-Solomon ECC generator polynomial on-the-fly
; else use built-in table
3. Define memory for code generation and displayed bitmap:
- qrTmpVars ds 9
- qrData ds QR_TOTAL
- qrPattern ds 1
- qrGenerator ds QR_DEGREE (only required if QR_GENERATE = 1)
- bitmap depends on platform
4. Implement two subroutines:
- GetPixel: checks the pixel at position x (Y), y (X), returns Z = 1 if not set
- InvertPixel: inverts the pixel at position x (Y), y (X)
5. Add the macros GEN_QR_CODE and QR_CODE_DATA to your code area
6. Add message text using the START_MSG, n x ADD_MSG_BYTE, STOP_MSG
7. Set qrPattern to 0..15 (chosing a mask pattern)
8. Call the GEN_QR_CODE macro
9. Draw the generated QR code bitmap
That's all! :)