Created
May 9, 2022 01:33
-
-
Save samneggs/60b287cc879aed762e530acac5e62777 to your computer and use it in GitHub Desktop.
Skiing game on Pi Pico in inline assembly with gc9a01 display
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
import gc9a01 | |
from machine import Pin, SPI, PWM, WDT | |
import framebuf | |
from usys import exit | |
import _thread | |
import array, gc | |
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep | |
from uctypes import addressof | |
from micropython import const | |
print('allocated memory',gc.mem_alloc()) | |
print('free memory', gc.mem_free()) | |
MAXSCREEN_X = const(240) | |
MAXSCREEN_Y = const(240) | |
GPIO_START = const(0x40014000) | |
TIMER_BASE = const(0x40054000) | |
# http://www.penguintutor.com/programming/picodisplayanimations | |
def blit_image_file(filename,width,height,cw,ch): # file width, file height, char width, char height | |
with open (filename, "rb") as file: | |
file_position = 0 | |
char_position = 0 | |
ecount = 0 | |
current_byte = file.read(4) # header | |
while file_position < (width * height * 2): | |
current_byte = file.read(1) | |
if len(current_byte) == 0: | |
break | |
sprite_buf[char_position] = ord(current_byte) | |
char_position += 1 | |
file_position += 1 | |
file.close() | |
#screen.blit(sprites,50,50) | |
#tft.blit_buffer(screen, 20, 0, MAXSCREEN_X, MAXSCREEN_Y) | |
#exit() | |
from ski_subs import game, char_map | |
def core1(): | |
global DONE, screen, control | |
#print(game(control)) | |
#DONE=True | |
#exit() | |
ret = 0 | |
gticks=ticks_us() | |
while 1: | |
ret = (game(control)) | |
tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y) | |
fps=1_000_000//ticks_diff(ticks_us(), gticks) | |
#print(fps) | |
gticks=ticks_us() | |
DONE = True | |
exit() | |
if __name__=='__main__': | |
spi = SPI(1, baudrate=63_000_000, sck=Pin(10), mosi=Pin(11)) | |
tft = gc9a01.GC9A01( | |
spi, | |
MAXSCREEN_X, | |
MAXSCREEN_Y, | |
reset=Pin(12, Pin.OUT), | |
cs=Pin(9, Pin.OUT), | |
dc=Pin(8, Pin.OUT), | |
backlight=Pin(13, Pin.OUT), | |
rotation=0) | |
tft.init() | |
tft.rotation(0) | |
tft.fill(gc9a01.BLACK) | |
DONE=False | |
display_buffer=bytearray(240*240*2) | |
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565) | |
sprite_buf=bytearray(32*32*2*12) | |
trees=array.array('I', 0 for _ in range(50)) | |
control = array.array('I',(addressof(screen),GPIO_START,100,200,0,1,addressof(sprite_buf),1,0xffff,addressof(trees), | |
1,0,TIMER_BASE,0,addressof(char_map),0,3,0,0,4,0,0,255)) | |
sprites=framebuf.FrameBuffer(sprite_buf,32 , 32*11, framebuf.RGB565) | |
blit_image_file('skier2.bin',32,32*11,32,32) | |
gc.collect() | |
print('remaining',gc.mem_free()) | |
sleep(.5) | |
_thread.start_new_thread(core1, ()) | |
sleep(.5) | |
while not DONE: | |
pass | |
exit() | |
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
#ski subs | |
from micropython import const | |
import array | |
MAXSCREEN_X = const(240) | |
MAXSCREEN_Y = const(240) | |
JOY_RIGHT = const(17*8) | |
JOY_DOWN = const(18*8) | |
JOY_SEL = const(19*8) | |
JOY_LEFT = const(20*8) | |
JOY_UP = const(21*8) | |
GPIO_START = const(0x40014000) | |
SCRN = const(0) | |
GPIO = const(4) | |
X_POS = const(8) | |
Y_POS = const(12) | |
X_VEL = const(16) | |
Y_VEL = const(20) | |
SPRITES = const(24) | |
PLAYER_NUM = const(28) | |
SCRN_COLOR = const(32) | |
TREES = const(36) | |
SPEED = const(40) | |
COLLIDE = const(44) | |
TIMER = const(48) | |
START_TIME = const(52) | |
CHAR_MAP = const(56) | |
ROW_ASM = const(0) | |
COL_ASM = const(2) | |
OFFSET_ASM = const(4) | |
COLOR_ASM = const(6) | |
PRINT_POS = const(60) | |
LIVES = const(64) | |
TUMBLE = const(68) | |
TREE_SCROLL= const(72) | |
NUM_TREES = const(76) | |
DISTANCE = const(80) | |
TREE_ADD = const(84) | |
SEED = const(88) | |
#control = array.array('I',(addressof(screen),GPIO_START,100,200,0,1,addressof(sprite_buf),1,0xffff,addressof(trees),1,0,TIMER_BASE,0,addressof(char_map))) | |
@micropython.asm_thumb | |
def game(r0): | |
ldr(r1,[r0,SEED]) | |
cmp(r1,255) | |
bne(CLEAR_SCREEN) | |
bl(RESET_TIME) | |
label(CLEAR_SCREEN) | |
ldr(r1,[r0,SCRN]) # screen base address | |
ldr(r2,[r0,SCRN_COLOR]) # white background | |
mov(r3,240) | |
mul(r3,r3) # 240*240 | |
add(r3,r3,r3) # (240*240)+(240*240) | |
add(r1,r1,r3) | |
label(CLEAR_LOOP) | |
strh(r2,[r1,0]) | |
sub(r1,2) | |
sub(r3,2) | |
bne(CLEAR_LOOP) | |
ldr(r1,[r0,Y_POS]) | |
mov(r2,210) # increase speed based on ypos | |
sub(r1,r2,r1) | |
asr(r1,r1,5) | |
str(r1,[r0,SPEED]) | |
ldr(r1,[r0,SPEED]) | |
ldr(r2,[r0,DISTANCE]) | |
add(r2,r2,r1) | |
str(r2,[r0,DISTANCE]) # total distance | |
ldr(r2,[r0,TREE_ADD]) | |
add(r2,r2,r1) | |
str(r2,[r0,TREE_ADD]) # distance to add a tree | |
cmp(r2,255) # add tree every 255 counts | |
blt(NO_ADD_TREE) | |
mov(r2,0) | |
str(r2,[r0,TREE_ADD]) | |
ldr(r6,[r0,NUM_TREES]) | |
add(r6,4) | |
str(r6,[r0,NUM_TREES]) # r6=new tree address | |
mov(r4,220) # max tree x-pos | |
bl(RANDOM) # r2=random number | |
lsl(r2,r2,8) | |
ldr(r1,[r0,TREES]) # address of tree array | |
add(r1,r1,r6) | |
str(r2,[r1,0]) | |
label(NO_ADD_TREE) | |
label(MOVE_PLAYER) | |
ldr(r1,[r0,X_POS]) | |
ldr(r2,[r0,X_VEL]) | |
asr(r2,r2,2) | |
add(r1,r1,r2) | |
cmp(r1,20) # min x limit | |
blt(X_LIM_LEFT) | |
cmp(r1,190) # max x limit | |
bgt(X_LIM_RIGHT) | |
str(r1,[r0,X_POS]) | |
mov(r1,0) | |
str(r1,[r0,TREE_SCROLL]) | |
b(TURNING) | |
label(X_LIM_LEFT) | |
mov(r1,2) | |
str(r1,[r0,TREE_SCROLL]) | |
mov(r1,0) | |
str(r1,[r0,X_VEL]) | |
b(TURNING) | |
label(X_LIM_RIGHT) | |
mov(r1,0) | |
sub(r1,2) | |
str(r1,[r0,TREE_SCROLL]) | |
mov(r1,0) | |
str(r1,[r0,X_VEL]) | |
label(TURNING) | |
ldr(r1,[r0,X_VEL]) # player turn sprites | |
add(r1,37) | |
mov(r2,5) # ->> | |
cmp(r1,55) | |
bgt(TURN_DONE) | |
mov(r2,4) # -> | |
cmp(r1,45) | |
bgt(TURN_DONE) | |
mov(r2,3) # - | |
cmp(r1,35) | |
bgt(TURN_DONE) | |
mov(r2,2) # <- | |
cmp(r1,25) | |
bgt(TURN_DONE) | |
mov(r2,1) # <<- | |
label(TURN_DONE) | |
str(r2,[r0,PLAYER_NUM]) # sprite number | |
label(JOYSTICK) | |
ldr(r1,[r0,GPIO]) # r1 = GPIO start address | |
mov(r2,JOY_RIGHT) | |
add(r2,r2,r1) | |
ldr(r2,[r2,0]) # read joy right | |
cmp(r2,0) | |
bne(CHECK_LEFT) | |
ldr(r2,[r0,X_VEL]) | |
add(r2,1) | |
str(r2,[r0,X_VEL]) | |
b(CHECK_DOWN) | |
label(CHECK_LEFT) | |
mov(r2,JOY_LEFT) | |
add(r2,r2,r1) | |
ldr(r2,[r2,0]) # read joy left | |
cmp(r2,0) | |
bne(NO_RIGHT_LEFT) | |
ldr(r2,[r0,X_VEL]) | |
sub(r2,1) # player left | |
str(r2,[r0,X_VEL]) | |
b(CHECK_DOWN) | |
label(NO_RIGHT_LEFT) | |
mov(r3,0) | |
str(r3,[r0,X_VEL]) # straight when no left/right | |
label(CHECK_DOWN) | |
mov(r2,JOY_DOWN) | |
add(r2,r2,r1) | |
ldr(r2,[r2,0]) | |
cmp(r2,0) | |
bne(CHECK_UP) | |
ldr(r3,[r0,Y_POS]) | |
cmp(r3,200) # bottom limit | |
bgt(CHECK_UP) | |
ldr(r2,[r0,Y_VEL]) | |
add(r3,r3,r2) | |
str(r3,[r0,Y_POS]) # move down | |
mov(r4,0) | |
str(r4,[r0,PLAYER_NUM]) # player slow | |
b(DRAW) | |
label(CHECK_UP) | |
mov(r2,JOY_UP) | |
add(r2,r2,r1) | |
ldr(r2,[r2,0]) | |
cmp(r2,0) | |
bne(DRAW) | |
ldr(r3,[r0,Y_POS]) | |
cmp(r3,20) # top limit | |
blt(DRAW) | |
ldr(r2,[r0,Y_VEL]) | |
sub(r3,r3,r2) | |
str(r3,[r0,Y_POS]) # move up | |
mov(r4,8) | |
str(r4,[r0,PLAYER_NUM]) # player fast | |
label(DRAW) | |
ldr(r6,[r0,NUM_TREES]) # r6=tree loop counter | |
label(TREE_LOOP) | |
ldr(r7,[r0,TREES]) # tree data base address | |
add(r7,r7,r6) | |
ldr(r2,[r7,0]) # tree data | |
ldr(r3,[r0,SPEED]) | |
mov(r4,0xff) | |
mov(r1,r2) | |
and_(r1,r4) # r1=y | |
cmp(r1,200) # y > 200? | |
blt(MOVE_TREE) | |
mov(r1,0) # reset y position | |
label(MOVE_TREE) | |
add(r1,r1,r3) # move tree down | |
asr(r2,r2,8) # move x to low byte | |
and_(r2,r4) # r2=x | |
ldr(r3,[r0,TREE_SCROLL]) | |
add(r3,r3,r2) # x+1 or x-1 scroll | |
cmp(r3,220) | |
blt(TREE_RIGHT) | |
mov(r3,2) | |
label(TREE_RIGHT) | |
cmp(r3,1) | |
bgt(TREE_LEFT) | |
mov(r3,219) | |
label(TREE_LEFT) | |
lsl(r3,r3,8) # move x to high byte | |
add(r3,r3,r1) # combine x and y | |
str(r3,[r7,0]) # | |
mov(r7,MAXSCREEN_X) | |
mul(r1,r7) # y*max_x | |
add(r1,r1,r2) # y*max_x + x | |
add(r1,r1,r1) # double for strh | |
ldr(r2,[r0,SCRN]) # base screen address | |
add(r1,r1,r2) # r1=address at x,y | |
mov(r2,9) | |
bl(DRAW_SPRITE) | |
sub(r6,r6,4) | |
cmp(r6,0) | |
bgt(TREE_LOOP) | |
# ------------------ Draw Player ------------- | |
ldr(r1,[r0,Y_POS]) # ypos | |
mov(r2,MAXSCREEN_X) | |
mul(r1,r2) # ypos*max_x | |
ldr(r2,[r0,X_POS]) | |
add(r1,r1,r2) # ypos*max_x+xpos | |
add(r1,r1,r1) # double for strh | |
ldr(r2,[r0,SCRN]) # screen address | |
add(r1,r1,r2) # r1=address at x,y | |
ldr(r2,[r0,TUMBLE]) | |
cmp(r2,0) | |
beq(NO_TUMBLE) | |
add(r2,10) | |
str(r2,[r0,TUMBLE]) | |
cmp(r2,255) | |
blt(DO_TUMBLE) | |
b(COLLIDE_EXIT) | |
label(DO_TUMBLE) | |
asr(r2,r2,5) | |
b(DRAW_TUMBLE) | |
label(NO_TUMBLE) | |
ldr(r2,[r0,PLAYER_NUM]) # sprite number | |
label(DRAW_TUMBLE) | |
mov(r7,0) | |
str(r7,[r0,COLLIDE]) # clear collision | |
bl(DRAW_SPRITE) | |
ldr(r6,[r0,SPEED]) | |
cmp(r6,0) | |
beq(NO_COLLIDE) # no collision at zero speed | |
ldr(r6,[r0,COLLIDE]) | |
cmp(r6,50) # points to determine collision | |
blt(NO_COLLIDE) | |
ldr(r6,[r0,TUMBLE]) | |
add(r6,1) | |
str(r6,[r0,TUMBLE]) | |
label(NO_COLLIDE) | |
label(SHOW_LIVES) # show sprites for lives | |
ldr(r6,[r0,LIVES]) | |
label(LIVES_LOOP) | |
ldr(r1,[r0,SCRN]) | |
mov(r3,MAXSCREEN_X) | |
lsl(r3,r3,5) | |
add(r3,r3,r1) | |
add(r3,80) | |
lsl(r2,r6,5) | |
add(r1,r3,r2) | |
mov(r2,3) | |
bl(DRAW_SPRITE) | |
sub(r6,1) | |
bne(LIVES_LOOP) | |
mov(r5,15) # time position | |
lsl(r5,r5,4) # offset | |
ldr(r2,[r0,SCRN]) # screen address | |
add(r2,r2,r5) # screen+offset | |
str(r2,[r0,PRINT_POS]) | |
bl(DISPLAY_TIME) # r2=elapse time | |
bl(DISPLAY_NUMBER) | |
mov(r5,240) # distance position | |
lsl(r5,r5,5) # offset | |
sub(r5,200) | |
ldr(r2,[r0,SCRN]) # screen address | |
add(r2,r2,r5) # screen+offset | |
str(r2,[r0,PRINT_POS]) | |
ldr(r2,[r0,DISTANCE]) # r2=distance | |
bl(DISPLAY_NUMBER) | |
b(EXIT) | |
# -------------------Subroutines--Draw Sprite------------- | |
# | |
label(DRAW_SPRITE) # r2=player number, r1=screen address, uses r1-r5,r7 | |
lsl(r2,r2,11) | |
ldr(r3,[r0,SPRITES]) # sprites base address | |
add(r2,r2,r3) # r2=sprite address | |
mov(r3,0) # r3=y | |
label(SPRITE_Y) | |
mov(r4,0) # r4=x | |
label(SPRITE_X) | |
ldrh(r5,[r1,0]) # check collision | |
ldr(r7,[r0,SCRN_COLOR]) | |
cmp(r5,r7) | |
beq(NO_COLLISION) | |
ldrh(r5,[r2,0]) # get player sprite | |
cmp(r5,r7) | |
beq(OVERLAP) | |
ldr(r7,[r0,COLLIDE]) | |
add(r7,1) | |
str(r7,[r0,COLLIDE]) | |
label(NO_COLLISION) | |
ldrh(r5,[r2,0]) # get player sprite | |
strh(r5,[r1,0]) # write to screen | |
label(OVERLAP) | |
add(r1,r1,2) | |
add(r2,r2,2) | |
add(r4,r4,1) | |
cmp(r4,32) | |
blt(SPRITE_X) | |
sub(r1,64) | |
mov(r5,240) | |
lsl(r5,r5,1) | |
add(r1,r1,r5) | |
add(r3,r3,1) | |
cmp(r3,32) | |
blt(SPRITE_Y) | |
bx(lr) | |
#-----------------------TIME ------------------- | |
label(RESET_TIME) | |
ldr(r1,[r0,TIMER]) | |
ldr(r1,[r1,0xc]) # low word of running timer | |
str(r1,[r0,START_TIME]) | |
bx(lr) | |
label(DISPLAY_TIME) # returns time in r2, uses r1 | |
ldr(r2,[r0,TIMER]) | |
ldr(r2,[r2,0xc]) # low word of running timer | |
ldr(r1,[r0,START_TIME]) | |
sub(r2,r2,r1) # elapsed = now - start | |
asr(r2,r2,16) # 10ths of seconds-ish | |
bx(lr) | |
#--------------------Display Number---disply r2---uses r1,r2,r3,r4,r5,r6,r7---------- | |
label(DISPLAY_NUMBER) | |
mov(r4,pc) # r4=control data | |
b(SKIP2) | |
data(2,0,2,4,0xff00 ) #row,col,offset,color | |
align(2) | |
label(SKIP2) | |
label(PRINT_LOOP) | |
push({r0,r1}) | |
mov(r0,r2) # num | |
mov(r1,10) # num//10 | |
mov(r7,lr) | |
bl(DIVIDE10) # do divide | |
mov(lr,r7) | |
mov(r6,r0) # r6=num//10 | |
pop({r1, r0}) | |
mov(r5,10) | |
mul(r5,r6) # 10*(num//10) | |
sub(r3,r2,r5) # r3=num-(10*(num//10)) | |
label(CHAR_LOOP) | |
mov(r2,r6) # r2=num//10 | |
mov(r5,7) | |
strh(r5,[r4,ROW_ASM]) # row=8 | |
label(ROW) | |
mov(r5,7) | |
strh(r5,[r4,COL_ASM]) # col=8 | |
label(COL) | |
push({r2}) | |
mov(r2,lr) | |
bl(PRINT) # print | |
mov(lr,r2) | |
pop({r2}) | |
ldrh(r5,[r4,COL_ASM]) | |
sub(r5,1) # col-=1 | |
strh(r5,[r4,COL_ASM]) | |
bpl(COL) | |
ldrh(r5,[r4,ROW_ASM]) | |
sub(r5,1) | |
strh(r5,[r4,ROW_ASM]) | |
bpl(ROW) | |
ldr(r5,[r0,PRINT_POS]) | |
sub(r5,16) # add one char | |
str(r5,[r0,PRINT_POS]) | |
cmp(r2,0) | |
beq(DONE_PRINT) # if num=0, exit | |
b(PRINT_LOOP) | |
label(DONE_PRINT) | |
bx(lr) | |
# ------------------ PRINT NUMBERS ------------------- | |
label(PRINT) # r3=digit, r4=control, uses r1,r5,r6,r7 | |
ldrh(r5,[r4,ROW_ASM]) | |
lsl(r7,r3,3) # r7=num*8 | |
add(r7,r7,r5) # r7=num*8 + row | |
ldr(r1,[r0,CHAR_MAP]) | |
add(r7,r7,r1) # c_map[(num*8)+row] | |
ldrb(r7,[r7,0]) # r7=c_map[(num*8)+row] | |
mov(r5,1) # r5=1 | |
ldrh(r6,[r4,COL_ASM]) # r6=col | |
lsl(r5,r6) # r5=1<<col | |
and_(r5,r7) # c_map[(num*8)+row] & 1<<col | |
beq(NOBIT) # no pixel, skip | |
ldrh(r5,[r4,ROW_ASM]) | |
mov(r7,MAXSCREEN_X) # screen width | |
add(r7,r7,r7) | |
mul(r7,r5) # row*width | |
add(r7,r7,r6) # r7 = row*width+col | |
add(r7,r7,r7) | |
ldr(r6,[r0,PRINT_POS]) # screen+offset | |
add(r7,r7,r6) # r7 = dest[row*200+col] | |
ldrh(r5,[r4,COLOR_ASM]) | |
strh(r5,[r7,0]) # dest[row*200+col] = white | |
add(r7,MAXSCREEN_X) | |
add(r7,MAXSCREEN_X) | |
strh(r5,[r7,0]) # dest[row*200+col] = white | |
label(NOBIT) | |
bx(lr) | |
# -------------------divide routine-----r0=r0//r1----uses r0,r1,r6-- | |
label(DIVIDE10) | |
mov(r6,0xd0) | |
lsl(r6,r6,24) # 0d0000000 | |
add(r6,0x60) # offset so strh will work | |
str(r0, [r6, 8]) # SIO_DIV_SDIVIDEND_OFFSET _u(0x00000068)8 | |
str(r1, [r6, 12]) # SIO_DIV_SDIVISOR_OFFSET _u(0x0000006c)12 | |
b(DELAY1) | |
label(DELAY1) | |
b(DELAY2) | |
label(DELAY2) | |
b(DELAY3) | |
label(DELAY3) | |
b(DELAY4) | |
label(DELAY4) | |
ldr(r1, [r6, 20]) #SIO_DIV_REMAINDER_OFFSET _u(0x00000074)20 | |
ldr(r0, [r6, 16]) #SIO_DIV_QUOTIENT_OFFSET _u(0x00000070)16 | |
bx(lr) | |
#----------------end divide---------------------------------------- | |
#---------------Initialize Player--------------- | |
label(INIT_PLAYER) | |
mov(r1,100) # reset x-pos | |
str(r1,[r0,X_POS]) | |
mov(r1,200) # reset y-pos | |
str(r1,[r0,Y_POS]) | |
mov(r1,1) | |
str(r1,[r0,X_VEL]) # reset velocities | |
str(r1,[r0,Y_VEL]) | |
mov(r1,0) | |
str(r1,[r0,TUMBLE]) # reset tumbling | |
mov(r3,lr) # save lr for double branch | |
bl(RESET_TIME) | |
mov(lr,r3) | |
bx(lr) | |
#---------------------# Random mumber --------------------- | |
label(RANDOM) # uses r1-r5, input=r4, output r2 | |
ldr(r1,[r0,SEED]) # seed | |
mov(r5,33) | |
mov(r2,r4) # r4 = max random number | |
label(HIGHBITS) # counts bits required | |
sub(r5,r5,1) | |
lsl(r2,r2,1) | |
bcc(HIGHBITS) # r5 = max bits | |
label(RANDOM_LOOP) | |
add(r1,13) # scramble seed | |
mov(r2,r1) # | |
mov(r3,9) | |
ror(r2,r3) | |
eor(r1,r2) # end scramble | |
mov(r2,r1) # r2 = random 32 bit number | |
str(r1,[r0,SEED]) | |
mov(r3,32) | |
sub(r3,r3,r5) | |
asr(r2,r3) # scale down to max random | |
mov(r3,1) | |
sub(r5,1) | |
lsl(r3,r5) # shift 17 bits to get offset | |
add(r2,r2,r3) # add offset for positive | |
#bmi(RANDOM_LOOP) # sometimes get negative? | |
cmp(r2,r4) # get another if too high | |
bgt(RANDOM_LOOP) | |
bx(lr) | |
# -------------------EXITS------------------ | |
label(COLLIDE_EXIT) | |
bl(INIT_PLAYER) | |
ldr(r1,[r0,LIVES]) | |
sub(r1,1) | |
cmp(r1,0) | |
bgt(LOSE_LIFE) | |
mov(r1,0) | |
str(r1,[r0,DISTANCE]) | |
str(r1,[r0,NUM_TREES]) | |
str(r1,[r0,TREE_ADD]) | |
mov(r1,3) # game over | |
label(LOSE_LIFE) | |
str(r1,[r0,LIVES]) | |
mov(r1,255) | |
lsl(r1,r1,18) | |
label(CRASH_PAUSE) | |
sub(r1,r1,1) | |
bne(CRASH_PAUSE) | |
mov(r0,1) | |
label(EXIT) | |
char_map=array.array('b',( | |
0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00, # U+0030 (0) | |
0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, # U+0031 (1) | |
0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00, # U+0032 (2) | |
0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00, # U+0033 (3) | |
0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00, # U+0034 (4) | |
0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, # U+0035 (5) | |
0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, # U+0036 (6) | |
0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, # U+0037 (7) | |
0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00, # U+0038 (8) | |
0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00)) # U+0039 (9) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment