Skip to content

Instantly share code, notes, and snippets.

Created October 29, 2012 10:24
Show Gist options
  • Save anonymous/3972820 to your computer and use it in GitHub Desktop.
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 )
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