Last active
December 18, 2015 20:49
-
-
Save Pharylon/5843026 to your computer and use it in GitHub Desktop.
Snake for Hackerspace Badges
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CON | |
_clkmode=xtal1+pll16x 'Run at 16x5 = 80mhz! | |
_xinfreq=5_000_000 'We are using a 5Mhz Crystal | |
GameSpeedMultiplier = 5 | |
StartingPixels = 4 | |
XBounds = 7 | |
YBounds = 6 | |
S2Pin = 17 | |
S3Pin = 18 | |
S4Pin = 19 | |
OBJ | |
rr: "RealRandom.spin" | |
printer: "LedPrinter" | |
VAR | |
byte SnakePixelsX[56] | |
byte SnakePixelsY[56] | |
byte CurrentLength | |
long DrawStack[20] | |
long MoveStack[20] | |
long InputStack[20] | |
long NumberArray[10] | |
byte GraphicsCogID | |
byte CurrentDirection ' 0 is up, 1 is right, 2 is down, 3 is left. | |
long Seed | |
byte FruitX | |
byte FruitY | |
byte FruitExists | |
long FruitValue | |
byte InputQueued | |
byte ButtonPressed | |
byte GameState '0 is pre-game 1, is during game, 2 is post-game. | |
long Score | |
PUB Main | |
cognew(Input, @InputStack) | |
cognew(OpeningDisplay, @DrawStack) | |
repeat while GameState == 0 | |
waitcnt(clkfreq/5 + cnt) | |
waitcnt(clkfreq + cnt) | |
initializeSnake | |
cognew(Graphics, @DrawStack) | |
GenerateFruit | |
repeat while GameState == 1 | |
GameTick | |
waitcnt(clkfreq/GameSpeedMultiplier + cnt) | |
waitcnt(clkfreq * 2 + cnt) | |
COGSTOP(GraphicsCogID) | |
EndGame | |
pri Input | |
repeat | |
if ina[S2Pin] == 0 AND InputQueued == 0 AND ButtonPressed == 0 | |
ButtonPressed := 1 | |
waitcnt(clkfreq/10 + cnt) | |
TurnCounterClockwise | |
WatchForButtonRelease(S2PIN) | |
elseif ina[S4Pin] == 0 AND InputQueued == 0 AND ButtonPressed == 0 | |
ButtonPressed := 1 | |
waitcnt(clkfreq/10 + cnt) | |
TurnClockwise | |
WatchForButtonRelease(S4PIN) | |
elseif ina[S3Pin] == 0 AND GameState == 0 | |
COGSTOP(GraphicsCogID) | |
GameState := 1 | |
pri WatchForButtonRelease (PIN) | i | |
repeat while i < 4 | |
if ina[PIN] == 1 | |
i++ | |
else | |
i := 0 | |
ButtonPressed := 0 | |
pri TurnCounterClockwise | |
if CurrentDirection == 0 AND InputQueued == 0 | |
CurrentDirection := 3 | |
elseif InputQueued == 0 | |
CurrentDirection -= 1 | |
InputQueued := 1 | |
pri TurnClockwise | |
if CurrentDirection == 3 AND InputQueued == 0 | |
CurrentDirection := 0 | |
elseif InputQueued == 0 | |
CurrentDirection += 1 | |
InputQueued := 1 | |
pri GameTick | collision,i | |
collision := DetectEatFruit | |
if collision == 1 | |
eatFruit | |
repeat i from CurrentLength -1 to 1 | |
SnakePixelsX[i] := SnakePixelsX[i - 1] | |
SnakePixelsY[i] := SnakePixelsY[i - 1] | |
if CurrentDirection == 0 | |
SnakePixelsY[0] += 1 | |
elseif CurrentDirection == 1 | |
SnakePixelsX[0] -= 1 | |
elseif CurrentDirection == 2 | |
SnakePixelsY[0] -= 1 | |
elseif CurrentDirection == 3 | |
SnakePixelsX[0] += 1 | |
InputQueued := 0 | |
DetectOutOfBounds | |
DetectSelfCollision | |
if FruitExists == 1 | |
FruitValue -= 1 | |
pri DetectSelfCollision | i,n | |
repeat i from 1 to CurrentLength - 1 | |
if SnakePixelsX[0] == SnakePixelsX[i] AND SnakePixelsY[0] == SnakePixelsY[i] | |
FruitX := SnakePixelsX[i] | |
FruitY := SnakePixelsY[i] | |
FruitExists := 1 | |
GameState := 2 | |
pri DetectOutOfBounds | |
if SnakePixelsX[0] > XBounds OR SnakePixelsY[0] > YBounds OR SnakePixelsX[0] < 0 OR SnakePixelsY[0] < 0 | |
GameState := 2 | |
FruitX := SnakePixelsX[1] | |
FruitY := SnakePixelsY[1] | |
PRI OpeningDisplay | |
GraphicsCogID := COGID | |
repeat while GameState == 0 | |
Printer.Print(string("PRESS S3 TO START")) | |
pri eatFruit | |
FruitExists := 0 | |
SnakePixelsX[currentLength] := SnakePixelsX[CurrentLength - 1] | |
SnakePixelsY[currentLength] := SnakePixelsY[CurrentLength - 1] | |
CurrentLength++ | |
Score += FruitValue | |
GenerateFruit | |
pri clearScreen | |
dira[20..27] := 0 | |
pri Graphics | i,Counter | |
GraphicsCogID := COGID | |
repeat | |
if GameState == 1 | |
repeat i from 0 to CurrentLength - 1 | |
lightPixel(SnakePixelsX[i], SnakePixelsY[i]) | |
elseif GameState == 2 | |
repeat i from 1 to CurrentLength - 1 | |
if SnakePixelsX[i] <> FruitX OR SnakePixelsY[i] <> FruitY | |
lightPixel(SnakePixelsX[i], SnakePixelsY[i]) | |
if FruitExists == 1 AND Counter > 50 | |
lightPixel(FruitX, FruitY) | |
Counter := 0 | |
Counter++ | |
pri GenerateFruit | collision | |
collision := 1 | |
repeat while collision == 1 | |
fruitX := Roll(0, 7) | |
fruitY := Roll(0, 6) | |
collision := DetectFruitCollision | |
FruitExists := 1 | |
FruitValue := 100 | |
pri DetectFruitCollision | collision, i | |
repeat i from 0 to CurrentLength - 1 | |
if FruitX == SnakePixelsX[i] AND FruitY == SnakePixelsY[i] | |
collision := 1 | |
return collision | |
pri DetectEatFruit | collision | |
if FruitX == SnakePixelsX[0] AND FruitY == SnakePixelsY[0] | |
collision := 1 | |
return collision | |
pri Roll(minValue, maxValue) : returnValue | |
returnValue := ||(Seed?//256) | |
repeat while returnValue < minValue OR returnValue > maxValue | |
returnValue := ||(Seed?//256) | |
return returnValue | |
pri lightPixel(X, Y) | |
dira[20..27] := 0 | |
dira[X + 20] := 1 | |
outa[X + 20] := 0 | |
if X > Y | |
dira[Y + 20] := 1 | |
outa[Y + 20] := 1 | |
else | |
dira[Y + 21] := 1 | |
outa[Y + 21] := 1 | |
pri EndGame | ScoreText,TempScore,i | |
COGNEW(DrawX, @DrawStack) | |
waitcnt(clkfreq + cnt) | |
COGSTOP(GraphicsCogID) | |
TempScore := Score | |
ScoreText := string("SCORE ") | |
if Score > 999 | |
i := (TempScore - (TempScore // 1000)) / 1000 | |
TempScore -= i * 1000 | |
bytemove(ScoreText+strsize(ScoreText),NumberArray[i],strsize(NumberArray[i])+1) | |
if Score > 99 | |
i := (TempScore - (TempScore // 100)) / 100 | |
TempScore -= i * 100 | |
bytemove(ScoreText+strsize(ScoreText),NumberArray[i],strsize(NumberArray[i])+1) | |
if Score > 9 | |
i := (TempScore - (TempScore // 10)) / 10 | |
TempScore -= i * 10 | |
bytemove(ScoreText+strsize(ScoreText),NumberArray[i],strsize(NumberArray[i])+1) | |
i := TempScore | |
bytemove(ScoreText+strsize(ScoreText),NumberArray[i],strsize(NumberArray[i])+1) | |
repeat | |
Printer.Print(ScoreText) | |
pri DrawX | i | |
GraphicsCogID := COGID | |
repeat | |
repeat i from 0 to 7 | |
lightPixel(i, i) | |
lightPixel(i, XBounds - (i + 1)) | |
Pri initializeSnake | |
CurrentDirection := 1 | |
CurrentLength := 4 | |
SnakePixelsX[0] := 4 | |
SnakePixelsY[0] := 3 | |
SnakePixelsX[1] := 5 | |
SnakePixelsY[1] := 3 | |
SnakePixelsX[2] := 6 | |
SnakePixelsY[2] := 3 | |
SnakePixelsX[3] := 7 | |
SnakePixelsY[3] := 3 | |
NumberArray[0] := string("0") | |
NumberArray[1] := string("1") | |
NumberArray[2] := string("2") | |
NumberArray[3] := string("3") | |
NumberArray[4] := string("4") | |
NumberArray[5] := string("5") | |
NumberArray[6] := string("6") | |
NumberArray[7] := string("7") | |
NumberArray[8] := string("8") | |
NumberArray[9] := string("9") | |
rr.Start | |
Seed := rr.Random | |
rr.Stop | |
dira[S2Pin] := 0 | |
dira[S3Pin] := 0 | |
dira[S4Pin] := 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
VAR | |
byte outArray[100] | |
byte message[4000] 'If your message is 10 characters, each character is 8x7 (56)bytes so 56*10=560 bytes. | |
byte letters[600] | |
PUB Print(longString) | X | |
SetLetters | |
clearArray(@message,3900) | |
DrawString(longString, @message, 30) | |
repeat X from 0 to 250 | |
clearArray(@outArray,80) | |
copyArray(@message,@outArray,X) | |
showArray(@outArray,10000) | |
waitcnt(clkfreq/25 + cnt) | |
PUB SetLetters | |
letters[48*6+0]:=%00000000 | |
letters[48*6+1]:=%01111110 | |
letters[48*6+2]:=%01000010 | |
letters[48*6+3]:=%01000010 | |
letters[48*6+4]:=%01000010 | |
letters[48*6+5]:=%01111110 | |
letters[48*6+6]:=%00000000 | |
letters[49*6+0]:=%00000000 | |
letters[49*6+1]:=%01110000 | |
letters[49*6+2]:=%00010000 | |
letters[49*6+3]:=%00010000 | |
letters[49*6+4]:=%00010000 | |
letters[49*6+5]:=%01111100 | |
letters[49*6+6]:=%00000000 | |
letters[50*6+0]:=%00000000 | |
letters[50*6+1]:=%01111110 | |
letters[50*6+2]:=%00000010 | |
letters[50*6+3]:=%01111110 | |
letters[50*6+4]:=%01000000 | |
letters[50*6+5]:=%01111110 | |
letters[50*6+6]:=%00000000 | |
letters[51*6+0]:=%00000000 | |
letters[51*6+1]:=%01111110 | |
letters[51*6+2]:=%00000010 | |
letters[51*6+3]:=%01111110 | |
letters[51*6+4]:=%00000010 | |
letters[51*6+5]:=%01111110 | |
letters[51*6+6]:=%00000000 | |
letters[52*6+0]:=%00000000 | |
letters[52*6+1]:=%01000010 | |
letters[52*6+2]:=%01111110 | |
letters[52*6+3]:=%00000010 | |
letters[52*6+4]:=%00000010 | |
letters[52*6+5]:=%00000010 | |
letters[52*6+6]:=%00000000 | |
letters[53*6+0]:=%00000000 | |
letters[53*6+1]:=%01111110 | |
letters[53*6+2]:=%01000000 | |
letters[53*6+3]:=%01111110 | |
letters[53*6+4]:=%00000010 | |
letters[53*6+5]:=%01111110 | |
letters[53*6+6]:=%00000000 | |
letters[54*6+0]:=%00000000 | |
letters[54*6+1]:=%01111100 | |
letters[54*6+2]:=%01000000 | |
letters[54*6+3]:=%01111110 | |
letters[54*6+4]:=%01000010 | |
letters[54*6+5]:=%01111110 | |
letters[54*6+6]:=%00000000 | |
letters[55*6+0]:=%00000000 | |
letters[55*6+1]:=%01111110 | |
letters[55*6+2]:=%01000010 | |
letters[55*6+3]:=%00000010 | |
letters[55*6+4]:=%00000010 | |
letters[55*6+5]:=%00000010 | |
letters[55*6+6]:=%00000000 | |
letters[56*6+0]:=%00000000 | |
letters[56*6+1]:=%01111110 | |
letters[56*6+2]:=%01000010 | |
letters[56*6+3]:=%01111110 | |
letters[56*6+4]:=%01000010 | |
letters[56*6+5]:=%01111110 | |
letters[56*6+6]:=%00000000 | |
letters[57*6+0]:=%00000000 | |
letters[57*6+1]:=%01111110 | |
letters[57*6+2]:=%01000010 | |
letters[57*6+3]:=%01111110 | |
letters[57*6+4]:=%00000010 | |
letters[57*6+5]:=%00000010 | |
letters[57*6+6]:=%00000000 | |
letters[65*6+0]:=%00000000 | |
letters[65*6+1]:=%00111100 | |
letters[65*6+2]:=%01000010 | |
letters[65*6+3]:=%01111110 | |
letters[65*6+4]:=%01000010 | |
letters[65*6+5]:=%01000010 | |
letters[65*6+6]:=%00000000 | |
letters[66*6+0]:=%00000000 | |
letters[66*6+1]:=%01111100 | |
letters[66*6+2]:=%01000010 | |
letters[66*6+3]:=%01111100 | |
letters[66*6+4]:=%01000010 | |
letters[66*6+5]:=%01111100 | |
letters[66*6+6]:=%00000000 | |
letters[67*6+0]:=%00000000 | |
letters[67*6+1]:=%00111110 | |
letters[67*6+2]:=%01000000 | |
letters[67*6+3]:=%01000000 | |
letters[67*6+4]:=%01000000 | |
letters[67*6+5]:=%00111110 | |
letters[67*6+6]:=%00000000 | |
letters[68*6+0]:=%00000000 | |
letters[68*6+1]:=%01111100 | |
letters[68*6+2]:=%01000010 | |
letters[68*6+3]:=%01000010 | |
letters[68*6+4]:=%01000010 | |
letters[68*6+5]:=%01111100 | |
letters[68*6+6]:=%00000000 | |
letters[69*6+0]:=%00000000 | |
letters[69*6+1]:=%01111110 | |
letters[69*6+2]:=%01000000 | |
letters[69*6+3]:=%01111110 | |
letters[69*6+4]:=%01000000 | |
letters[69*6+5]:=%01111110 | |
letters[69*6+6]:=%00000000 | |
letters[70*6+0]:=%00000000 | |
letters[70*6+1]:=%01111110 | |
letters[70*6+2]:=%01000000 | |
letters[70*6+3]:=%01111110 | |
letters[70*6+4]:=%01000000 | |
letters[70*6+5]:=%01000000 | |
letters[70*6+6]:=%00000000 | |
letters[71*6+0]:=%00000000 | |
letters[71*6+1]:=%00111110 | |
letters[71*6+2]:=%01000000 | |
letters[71*6+3]:=%01001110 | |
letters[71*6+4]:=%01000010 | |
letters[71*6+5]:=%00111100 | |
letters[71*6+6]:=%00000000 | |
letters[72*6+0]:=%00000000 | |
letters[72*6+1]:=%01000010 | |
letters[72*6+2]:=%01000010 | |
letters[72*6+3]:=%01111110 | |
letters[72*6+4]:=%01000010 | |
letters[72*6+5]:=%01000010 | |
letters[72*6+6]:=%00000000 | |
letters[73*6+0]:=%00000000 | |
letters[73*6+1]:=%01111110 | |
letters[73*6+2]:=%00010000 | |
letters[73*6+3]:=%00010000 | |
letters[73*6+4]:=%00010000 | |
letters[73*6+5]:=%01111110 | |
letters[73*6+6]:=%00000000 | |
letters[74*6+0]:=%00000000 | |
letters[74*6+1]:=%01111110 | |
letters[74*6+2]:=%00001000 | |
letters[74*6+3]:=%00001000 | |
letters[74*6+4]:=%01001000 | |
letters[74*6+5]:=%01110000 | |
letters[74*6+6]:=%00000000 | |
letters[75*6+0]:=%00000000 | |
letters[75*6+1]:=%01000110 | |
letters[75*6+2]:=%01011000 | |
letters[75*6+3]:=%01100000 | |
letters[75*6+4]:=%01011000 | |
letters[75*6+5]:=%01000110 | |
letters[75*6+6]:=%00000000 | |
letters[76*6+0]:=%00000000 | |
letters[76*6+1]:=%01000000 | |
letters[76*6+2]:=%01000000 | |
letters[76*6+3]:=%01000000 | |
letters[76*6+4]:=%01000000 | |
letters[76*6+5]:=%01111110 | |
letters[76*6+6]:=%00000000 | |
letters[77*6+0]:=%00000000 | |
letters[77*6+1]:=%01000010 | |
letters[77*6+2]:=%01100110 | |
letters[77*6+3]:=%01011010 | |
letters[77*6+4]:=%01000010 | |
letters[77*6+5]:=%01000010 | |
letters[77*6+6]:=%00000000 | |
letters[78*6+0]:=%00000000 | |
letters[78*6+1]:=%01000010 | |
letters[78*6+2]:=%01000010 | |
letters[78*6+3]:=%01100010 | |
letters[78*6+4]:=%01011010 | |
letters[78*6+5]:=%01000110 | |
letters[78*6+6]:=%00000000 | |
letters[79*6+0]:=%00000000 | |
letters[79*6+1]:=%00111100 | |
letters[79*6+2]:=%01000010 | |
letters[79*6+3]:=%01000010 | |
letters[79*6+4]:=%01000010 | |
letters[79*6+5]:=%00111100 | |
letters[79*6+6]:=%00000000 | |
letters[80*6+0]:=%00000000 | |
letters[80*6+1]:=%01111100 | |
letters[80*6+2]:=%01000010 | |
letters[80*6+3]:=%01111100 | |
letters[80*6+4]:=%01000000 | |
letters[80*6+5]:=%01000000 | |
letters[80*6+6]:=%00000000 | |
letters[81*6+0]:=%00000000 | |
letters[81*6+1]:=%00111100 | |
letters[81*6+2]:=%01000010 | |
letters[81*6+3]:=%01010010 | |
letters[81*6+4]:=%01100010 | |
letters[81*6+5]:=%01111100 | |
letters[81*6+6]:=%10000000 | |
letters[82*6+0]:=%00000000 | |
letters[82*6+1]:=%01111100 | |
letters[82*6+2]:=%01000010 | |
letters[82*6+3]:=%01111100 | |
letters[82*6+4]:=%01011000 | |
letters[82*6+5]:=%01000110 | |
letters[82*6+6]:=%00000000 | |
letters[83*6+0]:=%00000000 | |
letters[83*6+1]:=%00111100 | |
letters[83*6+2]:=%01000000 | |
letters[83*6+3]:=%00111100 | |
letters[83*6+4]:=%00000010 | |
letters[83*6+5]:=%01111100 | |
letters[83*6+6]:=%00000000 | |
letters[84*6+0]:=%00000000 | |
letters[84*6+1]:=%01111100 | |
letters[84*6+2]:=%00010000 | |
letters[84*6+3]:=%00010000 | |
letters[84*6+4]:=%00010000 | |
letters[84*6+5]:=%00010000 | |
letters[84*6+6]:=%00000000 | |
letters[85*6+0]:=%00000000 | |
letters[85*6+1]:=%01000010 | |
letters[85*6+2]:=%01000010 | |
letters[85*6+3]:=%01000010 | |
letters[85*6+4]:=%01000010 | |
letters[85*6+5]:=%00111100 | |
letters[85*6+6]:=%00000000 | |
letters[86*6+0]:=%00000000 | |
letters[86*6+1]:=%01000010 | |
letters[86*6+2]:=%01000010 | |
letters[86*6+3]:=%01000010 | |
letters[86*6+4]:=%00100100 | |
letters[86*6+5]:=%00011000 | |
letters[86*6+6]:=%00000000 | |
letters[87*6+0]:=%00000000 | |
letters[87*6+1]:=%01000010 | |
letters[87*6+2]:=%01000010 | |
letters[87*6+3]:=%01011010 | |
letters[87*6+4]:=%01100110 | |
letters[87*6+5]:=%01000010 | |
letters[87*6+6]:=%00000000 | |
letters[88*6+0]:=%00000000 | |
letters[88*6+1]:=%01000010 | |
letters[88*6+2]:=%00100100 | |
letters[88*6+3]:=%00011000 | |
letters[88*6+4]:=%00100100 | |
letters[88*6+5]:=%01000010 | |
letters[88*6+6]:=%00000000 | |
letters[89*6+0]:=%00000000 | |
letters[89*6+1]:=%01000010 | |
letters[89*6+2]:=%00100100 | |
letters[89*6+3]:=%00011000 | |
letters[89*6+4]:=%00011000 | |
letters[89*6+5]:=%00011000 | |
letters[89*6+6]:=%00000000 | |
letters[90*6+0]:=%00000000 | |
letters[90*6+1]:=%01111110 | |
letters[90*6+2]:=%00000100 | |
letters[90*6+3]:=%00011000 | |
letters[90*6+4]:=%00100000 | |
letters[90*6+5]:=%01111110 | |
letters[90*6+6]:=%00000000 | |
PUB DrawString(stringToSend,inArray,offset)|X | |
repeat X from 1 to StrSize(stringToSend) | |
DrawByteArray(byte[stringToSend][X-1],@byte[inArray],X*8+10+offset) | |
PUB DrawByteArray(inLetter,inArray,offset) | BY,BX | |
repeat BY from 0 to 6 | |
repeat BX from 0 to 7 | |
IF letters[(inLetter)*6+BY] >> BX &1==1 | |
byte[inArray][(7-BX+offset)*7+(6-BY)]:=1 | |
pub clearArray(inArray,arraySize)|x,y | |
repeat x from 0 to arraySize | |
byte[inArray][x]:=0 | |
pub showArray(inArray,cspeed)|x,y | |
repeat x from 0 to 7 | |
repeat y from 0 to 6 | |
if byte[inArray][(7-x)*7+y]==1 | |
light(y,x) | |
waitcnt(cspeed + cnt) | |
else | |
dira[20..27] := 0 | |
dira[20..27] := 0 | |
pub copyArray(inArray,oArray,offset)|x,y | |
repeat x from 0 to 7 | |
repeat y from 0 to 6 | |
if byte[inArray][(7-x+offset)*7+y]==1 | |
byte[oArray][(7-(x))*7+y]:=1 | |
pub light(Y, X) | |
dira[20..27] := 0 | |
dira[X+20] := 1 | |
outa[X+20] := 0 | |
if X+20 > Y+20 | |
dira[Y+20] := 1 | |
outa[Y+20] := 1 | |
else | |
dira[Y+20 + 1] := 1 | |
outa[Y+20 + 1] := 1 | |
{ | |
pub light(Y, X) | |
dira[0..8] := 0 | |
dira[X] := 1 | |
outa[X] := 0 | |
if X+20 > Y+20 | |
dira[Y] := 1 | |
outa[Y] := 1 | |
else | |
dira[Y+ 1] := 1 | |
outa[Y+ 1] := 1 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{{ | |
┌───────────────────────────────────────────┬────────────────┬───────────────────────────────────┬───────────────┐ | |
│ Real Random v1.2 │ by Chip Gracey │ Copyright (c) 2007 Parallax, Inc. │ 23 March 2007 │ | |
├───────────────────────────────────────────┴────────────────┴───────────────────────────────────┴───────────────┤ | |
│ │ | |
│ This object generates real random numbers by stimulating and tracking CTR PLL jitter. It requires one cog and │ | |
│ at least 20MHz. │ | |
│ │ | |
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ | |
│ Background and Detail: │ | |
│ │ | |
│ A real random number is impossible to generate within a closed digital system. This is because there are no │ | |
│ reliably-random states within such a system at power-up, and after power-up, it behaves deterministically. │ | |
│ Random values can only be 'earned' by measuring something outside of the digital system. │ | |
│ │ | |
│ In your programming, you might have used 'var?' to generate a pseudo-random sequence, but found the same │ | |
│ pattern playing every time you ran your program. You might have then used 'cnt' to 'randomly' seed the 'var'. │ | |
│ As long as you kept downloading to RAM, you saw consistently 'random' results. At some point, you probably │ | |
│ downloaded to EEPROM to set your project free. But what happened nearly every time you powered it up? You were │ | |
│ probably dismayed to discover the same sequence playing each time! The problem was that 'cnt' was always │ | |
│ powering-up with the same initial value and you were then sampling it at a constant offset. This can make you │ | |
│ wonder, "Where's the end to this madness? And will I ever find true randomness?". │ | |
│ │ | |
│ In order to have real random numbers, either some external random signal must be input, or some analog system │ | |
│ must be used to generate random noise which can be measured. We're in luck here, because it turns out that the │ | |
│ Propeller does have sufficiently-analog subsystems which can be exploited for this purpose -- each cog's CTR │ | |
│ PLLs. These can be exercised internally to good effect, without any I/O activity. │ | |
│ │ | |
│ This object sets up a cog's CTRA PLL to run at the main clock's frequency. It then uses a pseudo-random │ | |
│ sequencer to modulate the PLL's target phase. The PLL responds by speeding up and slowing down in a an endless │ | |
│ effort to lock. This results in very unpredictable frequency jitter which is fed back into the sequencer to │ | |
│ keep the bit salad tossing. The final output is a truly-random 32-bit unbiased value that is fully updated │ | |
│ every ~100us, with new bits rotated in every ~3us. This value can be sampled by your application whenever a │ | |
│ random number is needed. │ | |
│ │ | |
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ | |
│ Revision History v1.0 released 21 March 2007 │ | |
│ │ | |
│ v1.1 Bias removal has been added to ensure true randomness. Released 22 March 2007. │ | |
│ v1.2 Assembly code made more efficient. Documentation improved. Released 23 March 2007. │ | |
│ │ | |
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | |
}} | |
VAR | |
long cog, random_value | |
PUB start : okay | |
'' Start real random driver - starts a cog | |
'' returns false if no cog available | |
'Reset driver | |
stop | |
'Launch real random cog | |
return cog := cognew(@entry, @random_value) + 1 | |
'allow 5ms to launch and randomize | |
waitcnt(clkfreq / 200 + cnt) | |
PUB stop | |
'' Stop real random driver - frees a cog | |
'If already running, stop real random cog | |
if cog | |
cogstop(cog~ - 1) | |
PUB random : value | |
'' Returns a new long random value | |
'wait to insure new random (~200us at 80MHz system clock) | |
waitcnt($4000 + cnt) | |
return random_value | |
PUB random_ptr : ptr | |
'' Returns the address of the long which receives the random value | |
'' | |
'' A random bit is rotated into the long every ~3us, resuling in a | |
'' new long every ~100us, on average, at 80MHz. You may want to double | |
'' these times, though, to be sure that you are getting new bits. The | |
'' timing uncertainty comes from the unbiasing algorithm which throws | |
'' away identical bit pairs, and only outputs the different ones. | |
return @random_value | |
DAT | |
' ┌─────────────────────────┐ | |
' │ Real Random Generator │ | |
' └─────────────────────────┘ | |
org | |
entry movi ctra,#%00001_111 'set ctra to internal pll mode, select x16 tap | |
movi frqa,#$020 'set frqa to system clock frequency / 16 | |
movi vcfg,#$040 'set vcfg to discrete output, but without pins | |
mov vscl,#70 'set vscl to 70 pixel clocks per waitvid | |
:twobits waitvid 0,0 'wait for next 70-pixel mark ± jitter time | |
test phsa,#%10111 wc 'pseudo-randomly sequence phase to induce jitter | |
rcr phsa,#1 '(c holds random bit #1) | |
add phsa,cnt 'mix PLL jitter back into phase | |
rcl par,#1 wz, nr 'transfer c into nz (par shadow register = 0) | |
wrlong _random_value,par 'write random value back to spin variable | |
waitvid 0,0 'wait for next 70-pixel mark ± jitter time | |
test phsa,#%10111 wc 'pseudo-randomly sequence phase to induce jitter | |
rcr phsa,#1 '(c holds random bit #2) | |
add phsa,cnt 'mix PLL jitter back into phase | |
if_z_eq_c rcl _random_value,#1 'only allow different bits (removes bias) | |
jmp #:twobits 'get next two bits | |
_random_value res 1 | |
{{ | |
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | |
│ TERMS OF USE: MIT License │ | |
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ | |
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ | |
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ | |
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ | |
│is furnished to do so, subject to the following conditions: │ | |
│ │ | |
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ | |
│ │ | |
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ | |
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ | |
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ | |
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ | |
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | |
}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment