in the name of zero

October 10, 2009

beginning simple circuits analysis with kirchoffs laws

Filed under: hermetic studies

i’ve been rather consistent in my electrical learning with regards to schedule. the concepts, compelling, and i plan to drill the fundamentals (minus the hardcore physics stuff) in my head. my officemates have been more than helpful in explaining and teaching me the ways of electricity.

[ teaching the mind to do tricks is painful ]

the past nights, i’ve covered Ohm’s law and have solved some beginner problems.BUT - the thing i found frustrating at first was determining if a specific circuit is series or parallel - especially in bigger circuits with multiple paths. anyway, i’m over that frustration now and i’m beginning to have that automatic mental ability of re-drawing a circuit in my mind so i can see things clearly.

[ kirchoff’s law ]

“The algebraic sum of the currents into any point of the circuit must equal the algebraic sum of the currents going out of that point”

and

“The algebraic sum of all voltages in a loop must equal zero”

the first sample circuit problem is outlined below: solve for the current across resistor R3.

i reached only up to the two equations part since the I1 terms of both equations could not cancel out each other.

stuck halfway…

i still had 2 unkowns (I1 and I2). turning to the book, it said i need to normalize I1 in such a way that subtraction of those two equations will cancel out the terms with I1 - multiplying the second equation by 4.

there are many more problems i plan to solve but i’ve had enough kirchoffs law for one day.

October 3, 2009

kmap and boolean algebra

Filed under: hermetic studies

being your own teacher… is its own reward

i’ve been reading and learning about analog and digital electronics during my free time and during weekends. it has been a great learning experience and i wish i had a formal curriculum to follow with this gig. its been at most 4 years since i last used boolean algebra to this extent so im expecting things to be a bit rusty and wrong. i’m starting with the infamous 4 bit BCD to 7 segment since it’s the most basic, confidence boosting, hands-on activity i can think of.

[updates]

the problem with my initial kmaps was that they didn’t follow gray code. therefore, 00, 01, 10, 11 should have been 00, 01, 11, 00 wherein only a single bit changes everytime. a binary sequence from 01 to 10 changes two bits; 0 to 1, and 1 to 0 in their corresponding places.

i also noticed that the number of logic gates used to implement a 7 segment that displays 0x0-0xF is staggering and it would take up an exceedingly large space in my breadboard, so i lowered the digits it could display up to 9 only.

the figure below is my new truth table, with 10-15 as dont-cares.

which yields the following logic circuit for A to G.

but a simplification is still in order, mainly because there are combinations that yield a shorter sub-expression.

A = A + C + BD + B'D'
	
1) (A + C + BD + B'D')'              ; de morgan's
	
2) (A') (C') (B' + D') (B + D)       ; distribute
	
3) (A') (C') (B'B + B'D + BD' + D'D) ; theorem 16: A'A = 0
	
4) (A') (C') (B'D + BD')             ; A'B + AB' < => A xor B
	
5) ((A’) (C’) (B xor D))’            ; de morgan’s
	
6) A + C + (B xor D)’                ; final answer

assuming only single - 2 input cmos gates + sinle inverters

A + C + BD + B'D' = 6 gates
	
A + C + (B xor D)' = 4 gates

thats a savings of 2 logic gates!

the simplified XOR expression is very elegant, but i don’t have any CMOS xor gates in hand right now. so i’m sticking with the longer logic expressions which does not utilize an XOR operation.

November 8, 2008

let’s learn powerpc linux!

i’m actually using gcc4 and noticed that there are minor deviations
from the usual prolog/epilog functions since gcc3 when doing intel. i
have to read up on this.

so let’s try to follow a simple “hello world” program to see how gcc makes ppc
programs. it’s compiled with no optimizations.

int procedure1(const char *string)
{
        printf(string);
        return 0;
}
	
int main(int argc, char *argv[])
{
        return procedure1(\"hello world\n\");
}

the V4 stack frame.

	SP---->	+---------------------------------------+
		| back chain to caller			| 0
		+---------------------------------------+
		| saved LR				| 4
		+---------------------------------------+
		| Parameter save area (P)		| 8
		+---------------------------------------+
		| Alloca space (A)			| 8+P
		+---------------------------------------+
		| Local variable space (L)		| 8+P+A
		+---------------------------------------+
		| saved CR (C)				| 8+P+A+L
		+---------------------------------------+
		| Save area for GP registers (G)	| 8+P+A+L+C
		+---------------------------------------+
		| Save area for FP registers (F)	| 8+P+A+L+C+G
		+---------------------------------------+
	old SP->| back chain to caller's caller		|
		+---------------------------------------+

the V4 Registers

r0 volatile, may be used by function linkage
r1 stack pointer
r2 reserved for system
r3 .. r4 volatile, pass 1st - 2nd int args, return 1st - 2nd ints
r5 .. r10 volatile, pass 3rd - 8th int args
r11 .. r12 volatile, may be used by function linkage
r13 small data area pointer
r14 .. r31 saved
f0 volatile
f1 volatile, pass 1st float arg, return 1st float
f2 .. f8 volatile, pass 2nd - 8th float args
f9 .. f13 volatile
f14 .. f30 saved
f31 saved, static chain if needed.
lr volatile, return address
ctr volatile
xer volatile
fpscr volatile*
cr0 volatile
cr1 volatile**
cr2 .. cr4 saved
cr5 .. cr7 volatile

* The VE, OE, UE, ZE, XE, NI, and RN (rounding mode) bits of the FPSCR may be
changed only by a called function such as fpsetround that has the documented
effect of changing them, the rest of the FPSCR is volatile.

** Bit 6 of the CR (CR1 floating point invalid exception bit) is set to 1 if a
variable argument function is passed floating point arguments in registers.

the PPC architecture does not have a push/pop instruction that implicitly
operates on the stack. as such, stack management could be a little more “hands
on” on PPC in comparison to intel. the stack frame convention above is defined
to support parameter passing, reserved registers (nonvolatile) preservation and
local variables. each function which either calls another function or modifies
saved register must create a stack frame from memory set aside for use as a
stack defined by the r1 register (r1 = sp).

the stwu instruction assures that stack frame allocation is atomic. stack
space is allocated and the sp (r1) is updated in just one instruction.

parameter passing. ppc passes function parameters thru registers rather than
pushing them all in the stack.

<procedure1>
stwu    r1,-32(r1)  ; save former and allocate a new stack frame
mflr    r0          ; return addr of procedure1()
stw     r31,28(r1)  ; save r31
stw     r0,36(r1)   ; save r0
mr      r31,r1      ; mirror sp
stw     r3,8(r31)   ; save char * to stack
lwz     r3,8(r31)   ; argument to printf
bl      10010a00

li      r0,0        ; r0 = 0
mr      r3,r0       ; r3 = 0 = return value
lwz     r11,0(r1)   ; access back chain
lwz     r0,4(r11)   ; access return address
mtlr    r0          ; update link register with return addr of procedure1()
lwz     r31,-4(r11) ; restore r31
mr      r1,r11      ; restore caller’s stack
blr                 ; return to caller
	
<main>
stwu    r1,-32(r1)      ; save former frame and allocate a new stack frame
mflr    r0              ; return address of main()
stw     r31,28(r1)      ; save r31
stw     r0,36(r1)       ; save link register
mr      r31,r1          ; mirror sp
stw     r3,8(r31)       ; save r3
stw     r4,12(r31)      ; save r4
lis     r9,4096         ; lower 16 bits of string addr
addi    r3,r9,2176      ; higher 16 bits of string addr
bl      10000434
 ; procedure1(char *)
mr      r0,r3           ; r0 = return val of procedure1()
mr      r3,r0           ; r3 = 0 (retval)
lwz     r11,0(r1)       ; access back chain
lwz     r0,4(r11)       ; access return address
mtlr    r0              ; update link register
lwz     r31,-4(r11)     ; restore r31
mr      r1,r11          ; restore stack frame
blr                     ; leave main()

next time, we’ll delve more deeper and see how to access system calls directly
and how these system calls are implemented.

August 10, 2008

laptop love

Filed under: hermetic studies

i got annoyed because i have four extra keys on my laptop keyboard that doesn’t
work as expected when i’m in gentoo. i’m callin’ them “compaq keys” coz i dont
know what they are called and its tiresome to know anyway…

in windows vista:

compaq key1: starts a program ‘dvdplay’ i think…
compaq key2: toggles the volume on or off
compaq key3: lowers the volume
compaw key4: does the opposite of key3

so i modified my keymap settings so that compaq keys2-4 are mapped to function keys
F13-F15 (i only have F1 to F12…)

-- .Xmodmap --
keycode 160 = F13
keycode 174 = F14
keycode 176 = F15

and my corresponding .fluxbox/keys file

 -- snip --
	
# windows key
Mod4 x  :maximize
Mod4 d  :ShowDesktop
Mod4 a :ExecCommand aterm +sb -tr -trsb -fg darkgray -fade 50%
Mod4 w :ExecCommand audacious
Mod4 e :ExecCommand /usr/bin/emelfm2
Mod4 b :ExecCommand /usr/bin/firefox
Mod4 y :ExecCommand /usr/bin/gaim
Mod4 m :ExecCommand /usr/bin/sylpheed
Mod4 v :ExecCommand /usr/bin/gvim
	
# laptop keymap
F13 :ExecCommand /bin/bash ~/.mykbd
F14 :ExecCommand /usr/bin/amixer sset PCM 5%-
F15 :ExecCommand /usr/bin/amixer sset PCM 5%+
	
 -- snip -- 

now, volume on/off toggling presented a mild challenge mainly because i didn’t
find implicit mute/unmute capability in amixer’s man page. so i did a little bash
mojo to get the desired functionality i want.

.mykdb

#!/bin/bash
SYSMIX=`which amixer`
GET_SPKR_STAT=$SYSMIX
STATUS=`$GET_SPKR_STAT get Speaker | grep -i off`
	
if [[ -z $STATUS ]]; then
        $SYSMIX sset Speaker off 1> /dev/null
else
        $SYSMIX sset Speaker on 100% 1> /dev/null
fi  

it took me a whole goddamn 10 minutes to figure out that [[ ]] needs a space
separator on its expression field.

lesson learned. seriously, don’t do bash, brainfuck, and perl when you are sleep
deprived.

July 12, 2008

grainne2

i know how how it feels like to have a burning hole in your heart that can only be
filled with a loved one. but sometimes, we have no choice but to accept our
fate. - kenshin himura

it’s “grainne2″!! i decided to make it available here while i’m still waiting for the mods at crackmes.de to put it up. i’ll post a solution after a week or two..

update: crackmes.de page for “grainne2″ here. enjoy you guys..

dedicated to Grainne C. Yap - the girl who broke my heart.

June 29, 2008

witch yoo hee

i’m in love!

… but she’s married (in real life). this “koreanovela” is soo addicting!

June 28, 2008

linux raw spin locks

Filed under: hermetic studies

apparently, there are some issues with linux 2.6 and pearpc.. so i still cant
get the gentoo ppc to start properly. i thought i’d do some studying in the
meantime..

typedef struct {
        volatile unsigned int slock;
} raw_spinlock_t;
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{        asm volatile(\"\n1:\t\"
                     LOCK_PREFIX \" ; decb %0\n\t\"
                     \"jns 3f\n\"
                     \"2:\t\"
                     \"rep;nop\n\t\"
                     \"cmpb $0,%0\n\t\"
                     \"jle 2b\n\t\"
                     \"jmp 1b\n\"
                     \"3:\n\t\"
                     : \"+m\" (lock->slock) : : \"memory\");
}

interpretation of the extended inline asm:

1) : “+m” (locl->slock)
“+m” means that the memory operand ‘lock->slock’ is both input and output.

2) : “memory”
from gcc manual:
If your assembler instructions access memory in an unpredictable
fashion, add `memory’ to the list of clobbered registers. This will
cause GCC to not keep memory values cached in registers across the
assembler instruction and not optimize stores or loads to that memory.

3) LOCK_PREFIX is defined at /usr/src/linux/include/asm/alternative.h:

#define LOCK_PREFIX \
                \".section .smp_locks,\\"a\\"\n\"   \   ; push current section and change section to .smp_locks
                \"  .align 4\n\"                  \   ; align to 4 bytes
                \"  .long 661f\n\" /* address */  \   ; create an entry in the up/smp alternative locking table
                \".previous\n\"                   \   ; pop back the old section
                \"661:\n\tlock; \"                    ; assert processor LOCK# signal

LOCK_PREFIX is supposed to be called within the context of a procedure (executable) which finds its way to a .text section.

i haven’t digged down deep into the internals of ‘alternatives’ yet, but a quick look at kernel/alternative.c :: alternatives_smp_unlock() shows that it’s employing a self modifying code that patches the “lock” instruction with an architecture specific NOP opcode.

without all the extended asm semantics above, the asm roughly translates to:

1:      lock       ; decrement atomically
        decb    %0 ; really decrement now..
        jns     3f ; successful in acquiring lock?
2:      rep        ; nothing
        nop        ; nothing
        cmpb    $0, %0 ; someone must release the lock first.
        jle     2b     ; busy wait...
        jmp     1b     ; lock available! try acquiring lock again.
3:     ; exit __raw_spin_lock()

and then comes the trylock variant

static inline int __raw_spin_trylock(raw_spinlock_t *lock)
{
        char oldval;
        asm volatile(
                \"xchgb %b0,%1\"
                :\"=q\" (oldval), \"+m\" (lock->slock)
                :\"0\" (0) : \"memory\");
        return oldval > 0;
}

interpretation of the extended inline asm:

1) : “=q” (oldval)
output oldval in any a,b,c or d register.

2) : “+m” (locl->slock)
“+m” means that the memory operand ‘lock->slock’ is both input and output.

3) : “0″ (0)
%0 matches the output register for oldval. initialize that with the value 0.

4) : “memory”
from gcc manual:
If your assembler instructions access memory in an unpredictable
fashion, add `memory’ to the list of clobbered registers. This will
cause GCC to not keep memory values cached in registers across the
assembler instruction and not optimize stores or loads to that memory.

__raw_spin_trylock() basically exchanges the current value in raw_spinlock_t->slock with zero and returns true if locking was successful and false if acquiring of lock didn’t succeed.

lastly, we have the raw unlock procedure:

static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
        char oldval = 1;
	
        asm volatile(\"xchgb %b0, %1\"
                     : \"=q\" (oldval), \"+m\" (lock->slock)
                     : \"0\" (oldval) : \"memory\");
}

i haven’t been able to understand the significance of the “%b” in the assembler template but looking at the asm listing of the template with and without the %b yielded the same intructions, so could anyone shed some light on this one?

basically looks like __raw_spin_trylock(), but the difference is that oldval is now initialized to 1 instead of 0.

there are many variants stemming from the idea of this implementation. raw reader/writer locks which allows multiple readers but only one writer (with no concurrent readers). and then there’s the spinlock layer above the raw spinlock implementation.. but those are for another post.

’til then.

June 14, 2008

on my own and moving on

i’ve been puting off a lot of things lately. at the top of my list is to give some just attention to this little web space of mine. its not because i don’t have time anymore. its just that, i felt the need to explore some de-stressing activities other than writing my thoughts and rants down. i always found writing rather emotionally helpful, but during those carefree college days, i rarely
did anything to the point of exhaustion.

but im bringing my hiatus onto a peaceful end. good day! gentoo powerpc land!

April 7, 2008

still…

something i wish i have lots of right now… free time.

January 19, 2008

tying the 8259A pic to the ISRs

Filed under: hermetic studies

after i8259.c::init_IRQ() initializes the interrupt controller, it begins to
setup the interrupt descriptor table with it’s predefined ISR locations like so:

for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
	int vector = FIRST_EXTERNAL_VECTOR + i;
	if (i >= NR_IRQS)
		break;
	if (vector != SYSCALL_VECTOR)
		set_intr_gate(vector, interrupt[i]);
}

declared at hw_irq.h but defined and initialized via assembler constructs at entry.S, interrupt[] is an
array of ISR function pointers (to section irq_entries_start) that linux uses. i
removed the dwarf macros for clarity.

ENTRY(interrupt) interrupt[] address is in a .data section
.text
	
vector=0
ENTRY(irq_entries_start) // create a section called irq_entries_start in .text
.rept NR_IRQS
        ALIGN
1:      pushl $~(vector)	// save IRQ number, ~pt_regs->orig_eax
        jmp common_interrupt    // jump to common IRQ handling code
.data // now, back in our interrupt[] array at the .data section
        .long 1b		// place address of stub \"1\" in interrupt[i]
.text
vector=vector+1
.endr

then, common_interrupt is the one responsible for calling do_IRQ() which
will bring us back to the land of C. irq numbers are being passed in their two’s
complement form also.

putting it all together, the linux interrupt api

note: so this is basically intel 8259 pic specific.

in arch/i386/kernel/i8259.c, we could see a descriptor for the interrupt
controller being defined like so:

static struct irq_chip i8259A_chip = {
        .name           = "XT-PIC",		/* name used in /proc/interrupts */
        .mask           = disable_8259A_irq,	/* mask an interrupt source */
        .unmask         = enable_8259A_irq,	/* unmask an interrupt source */
        .mask_ack       = mask_and_ack_8259A, 	/* ack and mask an interrupt source */
};

struct irq_chip is defined at irq.h, there is a definitive explanation for each structure member there too. then, we also have the irq_desc structure which is a descriptor for each irq. it is also defined at irq.h. linux has a global array of irq_descriptor for the number of irqs defined by NR_IRQS. to get the descriptor for a specific irq is simply just a matter of adding an irqs interrupt number to get to the correct index in the irq_descriptor array.

disable_8259A() constructs a valid mask for the irq in question then checks to see if this irq is greater than 8. if it is, the mask is written to the slave pic, else, the mask is written to the master pic - remembering that irq 9-16 in the slave pic are cascaded to irq2 in the master pic.

enable_8259A() also follows the same pattern but it instead takes the one’s complement to turn on an interrupt bit.

mask_and_ack_8259A() sends a specific End Of Interrupt to the master PIC, or if irq > 8 to both the slave pic and the master pic in that order.

linux can tie a particular irq to the specific programmable interrupt controller with a specific interrupt code handler that would service the irq in question. in this writeup, linux assigns the first 16 interrupts to the i8529 pic with handle_level_irq() as the handler for them all.

we can see linux in action, setting the irq_descriptors and assigning the first 16 predefined irq to the intel 8259 pic in arch/i386/kernel/i8259.c::init_ISA_irqs(). specifically, in the following snippet:

for (i = 0; i < NR_IRQS; i++) {
	irq_desc[i].status = IRQ_DISABLED;
        irq_desc[i].action = NULL;
        irq_desc[i].depth = 1;
	
        if (i < 16) {
                 set_irq_chip_and_handler_name(i, &i8259A_chip,
                                               handle_level_irq, "XT");
	...
}

set_irq_chip_and_handler() is a wrapper to two functions, set_irq_chip() and __set_irq_handler(). the job of set_irq_chip() is to tie an irq descriptor to a specific interrupt chip and the job of __set_irq_handler() is simply to assign a handler to service the irq by assigning the handler address to the descriptor’s “handle_irq” member.

generic irq flow handlers:

handle_simple_irq
handle_level_irq
handle_edge_irq
handle_per_cpu_irq

they differ, primarly in how they handle an interrupt and successive interrupts
that happen at service time. all of the handlers eventually transfer control to
handle_IRQ_event() which will take
care of calling the list of irq action service routines.

[ installing irq action handlers ]

following irq/handle.c::handle_IRQ_event(), we could see it entering a
do-while() calling the handler of each action and then move to the next action
in the action list like so:

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
        ...
	do {
        	ret = action->handler(irq, action->dev_id);
                if (ret == IRQ_HANDLED)
                        status |= action->flags;
                retval |= ret;
                action = action->next;
        } while (action);
	...
}

the function responsible for installing these irq actions is found at irq/manage.c::setup_irq(). this function also registers an irq entry in /proc for the irq and it’s associated handler.

	...
	
                /* add new interrupt at end of irq queue */
                do {
                        p = &old->next;
                        old = *p;
                } while (old);
                shared = 1;
        }
	
        *p = new;
	
	...

struct irqaction is defined in interrupt.h as:

typedef irqreturn_t (*irq_handler_t)(int, void *);

struct irqaction {
        irq_handler_t handler;
        unsigned long flags;
        cpumask_t mask;
        const char *name;
        void *dev_id;
        struct irqaction *next;
        int irq;
        struct proc_dir_entry *dir;
};

going back to my original goal which is to understand how linux generates clock
ticks to make the scheduler work, i come upon mach-default/setup.c::time_init_hook() where the kernel installs an irqaction handler for irq0 - the timer interrupt.

static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, “timer”, NULL, NULL};

void __init time_init_hook(void)
{
        setup_irq(0, &irq0);
}

that’s it for now, it’s time for me to enjoy my weekend.

Get free blog up and running in minutes with Blogsome | Theme designs available here