Created
October 29, 2012 10:24
-
-
Save anonymous/3972820 to your computer and use it in GitHub Desktop.
Creates a bootcode.bin for dumping the OTP storage area over serial (gpio 14,15 : http://elinux.org/RPi_Low-level_peripherals#General_Purpose_Input.2FOutput_.28GPIO.29 )
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 os | |
r0 = 0 | |
r1 = 1 | |
r2 = 2 | |
r3 = 3 | |
r4 = 4 | |
r5 = 5 | |
r6 = 6 | |
r7 = 7 | |
r8 = 8 | |
r9 = 9 | |
r10 = 10 | |
r11 = 11 | |
r12 = 12 | |
r13 = 13 | |
r14 = 14 | |
r15 = 15 | |
r16 = 16 | |
r17 = 17 | |
r18 = 18 | |
r19 = 19 | |
r20 = 20 | |
r21 = 21 | |
r22 = 22 | |
r23 = 23 | |
r24 = 24 | |
r25 = 25 | |
r26 = 26 | |
r27 = 27 | |
r28 = 28 | |
r29 = 29 | |
r30 = 30 | |
r31 = 31 | |
class writer(object): | |
def __init__(self): | |
self.f = open("bootcode.bin", "wb") | |
self.labels= {} | |
self.todo = [] | |
def emit(self, a): | |
self.f.write(chr(a)) | |
def emit1(self, a): | |
self.emit(a&0xFF) | |
self.emit((a>>8) & 0xFF) | |
def emit2(self, a, b): | |
self.emit1(a) | |
self.emit1(b) | |
def emit3(self, a, b, c): | |
self.emit1(a) | |
self.emit1(b) | |
self.emit1(c) | |
def fillb(self, size, value): | |
for i in range(size/2): | |
self.emit1(value|(value<<8)) | |
def string(self, a): | |
for i in range(len(a)): | |
self.emit(ord(a[i])) | |
self.emit(0) # NULL | |
if len(a) % 2 == 0: | |
self.emit(0) # NULL to offset string to be even byte length | |
def create_label(self, name): | |
self.labels[name] = self.pc() | |
def label(self, name): | |
return self.labels.get(name, None) | |
def pc(self): | |
return self.f.tell() | |
def movi(self, reg, imm): | |
self.emit3(0xe800|(0x0<<5)|(reg), (imm)&0xffff, ((imm)>>16)&0xffff) | |
def addi(self, reg, imm): | |
self.emit3(0xe800|(0x2<<5)|(reg), (imm)&0xffff, ((imm)>>16)&0xffff) | |
def andi(self, reg, imm): | |
self.emit3(0xe800|(0x7<<5)|(reg), (imm)&0xffff, ((imm)>>16)&0xffff) | |
def cmpi(self, reg, imm): | |
self.emit3(0xe800|(0xa<<5)|(reg), (imm)&0xffff, ((imm)>>16)&0xffff) | |
def cmpgte(self, rd, rs, label): | |
# 1000 cccc 0000 dddd 01ss ssoo oooo oooo b<cc> rd, rs, $+o*2 if (rd <cc> rs) then branch | |
self.emit2(0x8300 | rd & 0x0F, 0x4000 | ((rs&0x0F) << 10) | ((self.label(label)-self.pc())/2)&0x3FF) | |
def ori(self, reg, imm): | |
self.emit3(0xe800|(0xd<<5)|(reg), (imm)&0xffff, ((imm)>>16)&0xffff) | |
def shri(self, ra, imm): | |
self.emit1(0x7a00|(ra)|(((imm)&0x1f)<<4)) | |
def shli(self, ra, imm): | |
self.emit1(0x7c00|(ra)|(((imm)&0x1f)<<4)) | |
def add(self, ra, rb): | |
self.emit1(0x4200|(ra)|((rb)<<4)) | |
def mov(self, ra, rb): | |
self.emit1(0x4000|(ra)|((rb)<<4)) | |
def st(self, reg1, reg2): | |
self.emit1(0x3000|(reg1)|((reg2)<<4)) | |
def ld(self, reg1, reg2): | |
self.emit1(0x2000|(reg1)|((reg2)<<4)) | |
def bne(self, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.bne, label, self.pc())) | |
o = 0 | |
else: | |
o = (self.label(label)-self.pc())/2 | |
self.emit1(0x1880|(o&0x7f)) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def bra(self, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.bra, label, self.pc())) | |
o = 0 | |
else: | |
o = (self.label(label)-self.pc())/2 | |
self.emit1(0x1f00|(o&0x7f)) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def beq(self, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.beq, label, self.pc())) | |
o = 0 | |
else: | |
o = (self.label(label)-self.pc())/2 | |
self.emit1(0x1800|(o&0x7f)) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def b(self, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.b, label, self.pc())) | |
o = 0 | |
else: | |
o = (self.label(label)-self.pc())/2 | |
self.emit1(0x1f00|(o&0x7f)) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def nop(self): | |
self.emit1(0x0001) | |
def btst(self, reg1, bit): | |
self.emit1(0x6C00 | ((bit & 0xF) << 4) | (reg1 & 0xF)) | |
def lea(self, reg, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.lea, reg, label, self.pc())) | |
o = 0 | |
else: | |
o = self.label(label)-self.pc() | |
self.emit3(0xe500|(reg), o&0xffff, (o>>16)&0xffff) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def ldb(self, reg1, reg2): | |
self.emit1(0x0c00|(reg1)|((reg2)<<4)) | |
def sub(self, reg1, reg2): | |
self.emit1(0x4600 | (((reg2&0xF) << 4) | (reg1&0xF))) | |
def bl(self, label, off=None): | |
if off is not None: | |
cur = self.pc() | |
self.f.seek(off, os.SEEK_SET) | |
if self.label(label) is None: | |
self.todo.append((self.bl, label, self.pc())) | |
o = 0 | |
else: | |
o = (self.label(label)-self.pc())>>1 | |
self.emit2(0x9080|((o>>16)&0x0f7f), o&0xffff) | |
if off is not None: | |
self.f.seek(cur, os.SEEK_SET) | |
def rts(self): | |
self.emit1(0x005a) | |
def save_lr(self): | |
self.emit1(0x03a1) | |
def restore_lr(self): | |
self.emit1(0x0321) | |
def finish(self): | |
for to in self.todo: | |
func = to[0] | |
args = to[1:] | |
func(*args) | |
#GLOBALS | |
GPFSEL1 = 0x7e200004 | |
GPSET0 = 0x7e20001c | |
GPCLR0 = 0x7e200028 | |
TIMER = 0x7E003004 | |
TARGET_BAUD_RATE = 115200 | |
# System clock is running directly off the 19.2MHz crystal at initial reset | |
SYSTEM_CLOCK = 19200000 | |
GPPUD = 0x7e200094 | |
GPPUDCLK0 = 0x7e200098 | |
AUX_ENABLES = 0x7e215004 | |
AUX_MU_IO_REG = 0x7e215040 | |
AUX_MU_IER_REG = 0x7e215044 | |
AUX_MU_IIR_REG = 0x7e215048 | |
AUX_MU_LCR_REG = 0x7e21504C | |
AUX_MU_MCR_REG = 0x7e215050 | |
AUX_MU_LSR_REG = 0x7e215054 | |
AUX_MU_MSR_REG = 0x7e215058 | |
AUX_MU_SCRATCH = 0x7e21505C | |
AUX_MU_CNTL_REG = 0x7e215060 | |
AUX_MU_STAT_REG = 0x7e215064 | |
AUX_MU_BAUD_REG = 0x7e215068 | |
#END GLOBALS | |
w = writer() | |
w.fillb(0x200, 0) | |
# Configure TX and RX GPIO pins for Mini Uart function. | |
w.movi(r1, GPFSEL1); | |
w.ld(r0, r1); | |
w.andi(r0, ~(7<<12)); | |
w.ori(r0, (2)<<12); | |
w.andi(r0, ~(7<<15)); | |
w.ori(r0, 2<<15); | |
w.st(r0, r1); | |
w.movi(r1, GPFSEL1) | |
w.ld(r0, r1) | |
w.andi(r0, ~(7<<18)) | |
w.ori(r0, 1<<18) | |
w.st(r0, r1) | |
w.movi(r1, GPPUD); | |
w.movi(r0, 0); | |
w.st(r0, r1); | |
w.movi(r0, 0); | |
#### START delay1 #### | |
w.create_label("delay1"); | |
w.nop(); | |
w.addi(r0, 1); | |
w.cmpi(r0, 150); | |
w.bne("delay1"); | |
w.movi(r1, GPPUDCLK0); | |
w.movi(r0, (1<<14)|(1<<15)); | |
w.st(r0, r1); | |
w.movi(r0, 0); | |
#### END delay1 #### | |
#### START delay2 #### | |
w.create_label("delay2") | |
w.nop(); | |
w.addi(r0, 1); | |
w.cmpi(r0, 150); | |
w.bne("delay2"); | |
w.movi(r1, GPPUDCLK0); | |
w.movi(r0, 0); | |
w.st(r0, r1); | |
# Set up serial port | |
w.movi(r1, AUX_ENABLES); w.movi(r0, 1); w.st(r0, r1); | |
w.movi(r1, AUX_MU_IER_REG); w.movi(r0, 0); w.st(r0, r1); | |
w.movi(r1, AUX_MU_CNTL_REG); w.movi(r0, 0); w.st(r0, r1); | |
w.movi(r1, AUX_MU_LCR_REG); w.movi(r0, 3); w.st(r0, r1); | |
w.movi(r1, AUX_MU_MCR_REG); w.movi(r0, 0); w.st(r0, r1); | |
w.movi(r1, AUX_MU_IER_REG); w.movi(r0, 0); w.st(r0, r1); | |
w.movi(r1, AUX_MU_IIR_REG); w.movi(r0, 0xC6); w.st(r0, r1); | |
w.movi(r1, AUX_MU_BAUD_REG); w.movi(r0, ((SYSTEM_CLOCK/(TARGET_BAUD_RATE*8))-1)); w.st(r0, r1); | |
w.movi(r1, AUX_MU_LCR_REG); w.movi(r0, 0x03); w.st(r0, r1); | |
w.movi(r1, AUX_MU_CNTL_REG); w.movi(r0, 3); w.st(r0, r1); | |
w.bl("awake_dragon") | |
for i in range(0x80): | |
w.movi(r0, i) | |
w.bl("hexstring"); | |
w.movi(r0, ord(' ')) | |
w.bl("put_char"); | |
w.movi(r0, ord(':')) | |
w.bl("put_char"); | |
w.movi(r0, ord(' ')) | |
w.bl("put_char"); | |
w.movi(r0, i) | |
w.bl("listen_dragon") | |
w.bl("hexstring"); | |
w.movi(r0, ord('\r')) | |
w.bl("put_char"); | |
w.movi(r0, ord('\n')) | |
w.bl("put_char"); | |
#### END delay2 #### | |
#### START loop #### | |
w.create_label("loop"); | |
# Wait char arrived in fifo | |
w.movi(r1, AUX_MU_LSR_REG); | |
w.ld(r0, r1); | |
w.andi(r0, 0x1); | |
w.cmpi(r0, 0x1); | |
w.bne("loop"); | |
# Push next character into serial fifo | |
w.movi(r1, AUX_MU_IO_REG); | |
w.ld(r0, r1); | |
w.st(r0, r1); | |
w.bra("loop"); | |
#### END loop #### | |
#### START hexstring #### | |
w.create_label("hexstring") | |
w.save_lr() | |
w.movi(r3, 0) | |
w.mov(r4, r0) | |
w.create_label("hexstring_loop") | |
w.mov(r1, r4) | |
w.andi(r1, 0xf0000000) | |
w.shri(r1, 28) | |
w.lea(r2, "digits") | |
w.add(r2, r1) | |
w.ldb(r0, r2) | |
w.bl("put_char") | |
w.shli(r4, 4) | |
w.addi(r3, 1) | |
w.cmpi(r3, 8) | |
w.bne("hexstring_loop") | |
w.restore_lr() | |
w.create_label("digits"); | |
w.string("0123456789abcdef") | |
w.create_label("put_char") | |
w.create_label("hexstring_putchar") | |
w.movi(r1, AUX_MU_LSR_REG) | |
w.ld(r1, r1) | |
w.andi(r1, 0x20) | |
w.cmpi(r1, 0x20) | |
w.bne("hexstring_putchar") | |
w.movi(r1, AUX_MU_IO_REG) | |
w.st(r0, r1) | |
w.rts() | |
#### END hexstring #### | |
#### START Dragon #### | |
""" Awake the dragon """ | |
w.create_label("awake_dragon") | |
w.save_lr() | |
w.movi(r3, 3) | |
w.movi(r1, 0x7E20F004) | |
w.st(r3, r1) | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.movi(r3, 0) | |
w.movi(r1, 0x7E20F00C) | |
w.st(r3, r1) | |
w.movi(r1, 0x7E20F008) | |
w.st(r3, r1) | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.movi(r3, 2) | |
w.movi(r1, 0x7E20F004) | |
w.st(r3, r1) | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.restore_lr() | |
""" Sing the dragon to sleep """ | |
w.create_label("bore_dragon") | |
w.save_lr() | |
w.movi(r3, 0) | |
w.movi(r1, 0x7E20F00C) | |
w.st(r3, r1) | |
w.movi(r1, 0x7E20F008) | |
w.st(r3, r1) | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.movi(r3, 0) | |
w.movi(r1, 0x7E20F004) | |
w.st(r3, r1) | |
w.restore_lr() | |
""" Listen to the dragon """ | |
w.create_label("listen_dragon") | |
w.save_lr() | |
w.movi(r1, 0x7E20F01C) | |
w.st(r0, r1) | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.ld(r1, r1) | |
w.movi(r3, 0) | |
w.movi(r1, 0x7E20F00C) | |
w.st(r3, r1) | |
w.movi(r1, 0x7E20F008) | |
w.st(r3, r1) | |
w.movi(r0, 0x28) | |
w.bl("wait_cycles") | |
w.movi(r1, 0x7E20F008) | |
w.ld(r1, r1) | |
w.movi(r3, 1) | |
w.movi(r1, 0x7E20F008) | |
w.st(r3, r1) | |
w.movi(r1, 0x7E20F008) | |
w.ld(r1, r1) | |
w.create_label("listen_loop") | |
w.movi(r0, 0x14) | |
w.bl("wait_cycles") | |
w.movi(r1, 0x7E20F010) | |
w.ld(r1, r1) | |
w.btst(r1, 0) | |
w.beq("listen_loop") | |
w.movi(r1, 0x7E20F018) | |
w.ld(r0, r1) | |
w.restore_lr() | |
""" Wait cycles """ | |
w.create_label("wait_cycles") | |
w.b("wait_cycles_loop") | |
w.create_label("wait_cycles_nop") | |
w.nop() | |
w.create_label("wait_cycles_loop") | |
w.cmpi(r0, 0) | |
w.addi(r0, -1) | |
w.bne("wait_cycles_nop") | |
w.rts() | |
#### END Dragon #### | |
#fixup labels | |
w.finish() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment