Esempio n. 1
0
void handler_dev_arm_write(u2_t addr, u1_t data)
{

	assert (addr == WREG_LDACCW || addr == WREG_LDACSTART || addr == WREG_LDACSTOP ||
		addr == WREG_O2 || addr == WREG_O1 || addr == WREG_O3);

#ifdef DEBUG
	if (trace_regs) {
		if ((addr == WREG_O3) && isActive(O3_N3_OVRST, data)) printf("R3 "); else
		if ((addr == WREG_O3) && isActive(O3_N0_OVRST, data)) printf("R0 "); else
		printf("%s=%02x ", arm_wreg[addr - ADDR_ARM(0)], data);
	}
#endif

	// let PRU count N0/N3 overflows while measuring
	// FIXME: is this test valid for all measurement modes? O2_ARM_EN instead? TI +/- vs +only mode?
	if ((addr == WREG_O2) && isActive(O2_MAN_ARM, data)) {
		num_meas++;
		if (meas_time == 0) meas_time = timer_ms();

#ifdef DEBUG
		if (trace_regs) { printf("* "); fflush(stdout); }
#endif
		freq_record(0, REG_STR, 0, 0, 0, "* ");

		if (use_pru) {
			#if 0
			//assert(pru->count == PRU_DONE);
			if (pru->count != PRU_DONE) {
				printf("write O2_MAN_ARM: pru->count != PRU_DONE? [i.e. PRU never saw EOM]\n");
			}
			#endif
			
			bus_write(addr, data);	// let arm command go through
			n3_ovfl_sent = n0_ovfl_sent = ovfl_none = 0;

			send_pru_cmd(PRU_CLEAR);

			hold_off = TRUE;
			pru->count = PRU_COUNT;
			return;
		}
	}

	// ignore WREG_O3 writes to clear overflow bits while PRU is doing it
	if (use_pru && hold_off && (addr == WREG_O3)) {
		return;
	}

#ifdef FREQ_DEBUG
	if (use_pru && !hold_off) {
		if (addr == WREG_O3) {
			if (isActive(O3_N3_OVRST, data) || isActive(O3_N0_OVRST, data))
				freq_record(0, REG_READ, addr, data, 0, 0);
		}
	}
#endif

	bus_write(addr, data);
}
Esempio n. 2
0
static void bus_write_string(char *buf, char *str){
	int len = strlen(str);
	int i = 0;
	for (i = 0; i < len; i++){
		bus_write(8, buf + i, *((char *)(str + i)));
	}
	bus_write(8, buf + i, '\0');
}
Esempio n. 3
0
void fake_master::run()
{    
    uint32_t data = 0;
    uint32_t addr = 0;
    uint32_t length = 4;

        bus_write(data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        data += 100;
        bus_write(data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        data += 100;
        bus_write(data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        data += 100;
        bus_write(data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        data += 100;
        bus_write(data, addr, 4);
        wait(200, SC_NS);

        addr = 0;
        bus_read(&data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        bus_read(&data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        bus_read(&data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        bus_read(&data, addr, 4);
        wait(200, SC_NS);

        addr += 4;
        bus_read(&data, addr, 4);
        wait(200, SC_NS);

}
Esempio n. 4
0
void ds1302_write(unsigned char addr, unsigned char val)
{
	CLR_RST;
	bus_nop;
	CLR_CLK;
	bus_nop;
	SET_RST;    //enable chip
	bus_nop;
	bus_write(addr); /* 地址,命令 */
	bus_write(val); /* 写1Byte数据*/
	SET_CLK;
	bus_nop;
	CLR_RST;
	bus_nop; 
}
Esempio n. 5
0
int
main(int argc, char *argv[])
{
	bus_t bus;
	int i;
	if (argc < 2)
		return fprintf(stderr, "USAGE: %s daemon...", *argv), 2;
	t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY));

	for (i = 1; i < argc; i++) {
		sprintf(arg, "grep '^%s$' < \"${XDG_RUNTIME_DIR}/started-daemons\" >/dev/null", argv[i]);
		if (WEXITSTATUS(system(arg))) {
			sprintf(arg, "%ji require %s", (intmax_t)getppid(), argv[i]);
			t(bus_write(&bus, arg, 0));
		}
	}

	bus_close(&bus);
	return 0;

fail:
	perror("require");
	bus_close(&bus);
	return 1;
}
Esempio n. 6
0
int FASTCALL ppc_write_effective_word(uint32 addr, uint32 data)
{
	PPC_CPU_State* cpu = get_current_cpu();
        e500_core_t * current_core = get_current_core();
	uint32 p;
	int r;
	if(addr & 0x3){
		//ppc_exception for unalign
	}
	if (!((r=ppc_effective_to_physical(current_core, addr, PPC_MMU_WRITE, &p)))) {
		if(in_ccsr_range(p)){
			int offset = p - current_core->get_ccsr_base(cpu->ccsr);
			//skyeye_config.mach->mach_io_write_word(&gCPU, offset, data);
			skyeye_config_t* config = get_current_config();
			config->mach->mach_io_write_word(cpu, offset, data);
			//printf("DBG:write to CCSR,value=0x%x,offset=0x%x,pc=0x%x\n", data, offset,current_core->pc);
		}
		else{
			bus_write(32, p, data);	
                        //fprintf(stderr,"in %s, can not find address 0x%x,pc=0x%x,ccsr_base=0x%x, ccsr=0x%x\n", __FUNCTION__, p, current_core->pc, GET_CCSR_BASE(gCPU.ccsr), gCPU.ccsr);
                        //skyeye_exit(-1);
            }
	}
	return r;
}
Esempio n. 7
0
File: busio.c Progetto: joaohf/dtree
int perform_write(const char *dev, uint32_t addr, uint32_t len, uint32_t value)
{
	struct dtree_dev_t *d = dtree_byname(dev);
	if(d == NULL) {
		fprintf(stderr, "No device '%s' found\n", dev);
		return 1;
	}

	dtree_addr_t base = dtree_dev_base(d);
	dtree_addr_t high = dtree_dev_high(d);

	if(base < high) {
		if(base + addr + len > high) {
			verbosity_printf(1, "Address is out of range of the device: 0x%08X (high: 0x%08X)", base + addr, high);
			return 2;
		}
	}

	verbosity_printf(1, "Action: write, device: '%s', offset: '0x%08X', data: '0x%08X', len: '%d'", dev, addr, value, len);

	bus_write(dtree_dev_base(d), addr, value, len);

	dtree_dev_free(d);
	return 0;
}
Esempio n. 8
0
inline void register_write(uint8_t reg, uint8_t value)
/* Write to register
  
   Writes a value to an APU register by feeding the 6502
   with instructions for loading the value into A, and then
   storing the value in $40<reg>.
*/
{
  // Put STA_zp on bus before deactivating CPU latch
  bus_write(STA_zp);

  // Open latch output
  bus_select(CPU_ADDRESS);

  // The code in the register set function has to be cycle exact, so it has to
  // be run with interrupts disabled:
  
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 
    register_set(reg, value);
  }

  // Finally, latch the last bus value by deselecting the CPU
  bus_deselect();

  // Reflect change in mirror
  reg_mirror[reg] = value;
}
Esempio n. 9
0
int FASTCALL ppc_write_effective_byte(uint32 addr, uint8 data)
{
	uint32 p;
        int r;
	e500_core_t* current_core = get_current_core();
	PPC_CPU_State* cpu = get_current_cpu();
        if (!((r=ppc_effective_to_physical(current_core, addr, PPC_MMU_WRITE, &p)))) {
		//ppc_io_write_byte (&current_core-> p, data);

                //printf("DBG:in %s,addr=0x%x,p=0x%x, data=0x%x, pc=0x%x\n", __FUNCTION__, addr,p, data, current_core->pc);
                //printf("DBG:ccsr=0x%x,CCSR_BASE=0x%x",current_core->ccsr.ccsr,GET_CCSR_BASE(current_core->ccsr.ccsr));
		if(in_ccsr_range(p)){
                        int offset = p - current_core->get_ccsr_base(cpu->ccsr);
			//skyeye_config.mach->mach_io_write_byte(&gCPU, offset, data);
			skyeye_config_t* config = get_current_config();
			config->mach->mach_io_write_byte(cpu, offset, data);
			return r;
                        //printf("DBG:write to CCSR,value=0x%x,offset=0x%x\n", data, offset);
                }
		        else{
			bus_write(8, p, data);
                        //fprintf(stderr,"in %s, can not find address 0x%x,pc=0x%x,ccsr=0x%x\n", __FUNCTION__, p, current_core->pc, gCPU.ccsr);
                        //skyeye_exit(-1);
                }
        }
        return r;
}
Esempio n. 10
0
u4_t dsp_leds_write(u4_t a, u1_t d)
{
	if (!dsp_7seg_ok) return 0;
	
	dsp_leds_cache[a] = d;
	bus_write(ADDR_LEDS(a), d);
	
	return 0;
}
Esempio n. 11
0
File: mtd.cpp Progetto: char32/24aa
size_t Mtd::fitted_write(const uint8_t *txdata, size_t len, uint32_t offset) {

  osalDbgAssert(len != 0, "something broken in higher level");
  osalDbgAssert((offset + len) <= (cfg.pages * cfg.pagesize),
             "Transaction out of device bounds");
  osalDbgAssert(((offset / cfg.pagesize) == ((offset + len - 1) / cfg.pagesize)),
             "Data can not be fitted in single page");

 return bus_write(txdata, len, offset);
}
Esempio n. 12
0
// c == 0 means there is no underlying string char generating this 7-segment digit
// i.e. we're being called from interpreted code
u4_t dsp_7seg_write(u4_t pos, char c, u1_t d)
{
	if (!dsp_7seg_ok) return 0;
	dsp_numeric = c? FALSE : TRUE;
	
	dsp_char_cache[pos] = c;
	dsp_7seg_cache[pos] = d;
	bus_write(ADDR_7SEG(pos), d);
	//if (c) { printf("%d", pos); if (c==' ') c='_'; if (c) printf(":%c ", c); else printf("=%02x ", d); if (pos==15) printf("\n"); fflush(stdout); }
	
	return 0;
}
Esempio n. 13
0
void io_reset_pc()
{
  bus_write(STA_zp);

  bus_select(CPU_ADDRESS);

  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    reset_pc();
  }
  
  bus_deselect();
}
Esempio n. 14
0
/*
 * load a block of data to the memory.
 */
exception_t load_data(void* src, size_t len, generic_address_t load_addr){
	char* p = src;
	generic_address_t addr = load_addr;
	int i = 0;
	while(i < len){
		//skyeye_log(Debug_log, __FUNCTION__, "data=0x%x,addr=0x%x\n", *(p + i), addr);
		bus_write(8, addr, *(p + i));
		addr++;
		i++;
	}
	return No_exp;
}
Esempio n. 15
0
/*
 * 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 控制
 * 8Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B 1B
 */
void ds1302_write_burst(unsigned char *data)
{
	unsigned char i;
	DS1302_WP_DIS;/* 控制命令,WP=0,写操作?*/
	CLR_RST;
	bus_nop;
	CLR_CLK;
	bus_nop;
	SET_RST;
	bus_nop;
	bus_write(DS1302_CLKBURST_Reg); /* 0xbe:时钟多字节写命令 */
	for (i=8;i>0;i--) /*8Byte = 7Byte 时钟数据 + 1Byte 控制*/
	{
		bus_write(*val);/* 写1Byte数据*/
		val++;
	}
	SET_CLK;
	bus_nop;
	CLR_RST;
	DS1302_WP_EN;
}
Esempio n. 16
0
static void arch_mips_write_memory(cpu_t *cpu, addr_t addr, uint32_t value, uint32_t size)
{
	uint32_t pa = addr;
	/* if pa is located at kseg0 */
	if(pa >= 0x80000000 && pa < 0xA0000000)
		pa = pa & ~0x80000000;

	/* if pa is located at kseg1 */
	if(pa >= 0xa0000000 && pa < 0xC0000000)
		pa = pa & ~0xE0000000;

	bus_write(size, addr, value);
}
Esempio n. 17
0
/* wb_write_words :put words in Write Buffer
 * @state:	ARMul_State
 * @wb_t:	write buffer
 * @pa:		physical address
 * @data:	data ptr
 * @n		number of word to write
 *
 * Note: write buffer merge is not implemented, can be done late
 * */
void
mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
		    ARMbyte * data, int n)
{
	int i;
	wb_entry_t *wb;

	while (n) {
		if (wb_t->num == wb_t->used) {
			/*clean the last wb entry */
			ARMword t;

			wb = &wb_t->entrys[wb_t->last];
			t = wb->pa;
			for (i = 0; i < wb->nb; i++) {
				//mem_write_byte (state, t, wb->data[i]);
				bus_write(8, t, wb->data[i]);
				//t += WORD_SIZE;
				t++;
			}
			wb_t->last++;
			if (wb_t->last == wb_t->num)
				wb_t->last = 0;
			wb_t->used--;
		}

		wb = &wb_t->entrys[wb_t->first];
		i = (n < wb_t->nb) ? n : wb_t->nb;

		wb->pa = pa;
		//pa += i << WORD_SHT;
		pa += i;

		wb->nb = i;
		//memcpy(wb->data, data, i << WORD_SHT);
		memcpy (wb->data, data, i);
		data += i;
		n -= i;
		wb_t->first++;
		if (wb_t->first == wb_t->num)
			wb_t->first = 0;
		wb_t->used++;
	};
//teawater add for set_dirty fflash cache function 2005.07.18-------------------
#ifdef DBCT
	if (!skyeye_config.no_dbct) {
		tb_setdirty (state, pa, NULL);
	}
#endif
//AJ2D--------------------------------------------------------------------------
}
Esempio n. 18
0
u4_t dsp_7seg_dp(u4_t pos)
{
	if (!dsp_7seg_ok) return 0;
	
	u1_t d = dsp_7seg_cache[pos];
	d |= DP;
	dsp_7seg_cache[pos] = d;
	bus_write(ADDR_7SEG(pos), d);

	if (dsp_char_cache[pos]) {
		dsp_char_cache[pos] |= DP;
	}

	return 0;
}
Esempio n. 19
0
int main(int argc, char *argv[])
{
	bus_t bus;
	if (argc < 3)
		return fprintf(stderr, "USAGE: %s state daemon", *argv), 2;
	t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY));
	sprintf(arg, "%ji %s %s", (intmax_t)getppid(), argv[1], argv[2]);
	t(bus_write(&bus, arg));
	t(bus_close(&bus));
	return 0;

fail:
	perror("announce");
	return 1;
}
Esempio n. 20
0
/* write memory by external modules */
void ARMV5::memWrite(uint32_t data, uint32_t vir, int size)
{
    /* NOTE: don't use data_write() function directly, or it probably brings some bizarre side effects */
    uint32_t phy = 0;
    bool cache = true;

    if (mmu_enable) {
        vir2phy(vir, &phy, CPSR_MODE(rf.cpsr), true, &cache);
    }

    else {
        phy = vir;
    }

    bus_write(data, phy, size);
}
Esempio n. 21
0
int bus_send_done(struct bus_descriptor* bus, bus_addr_t daddr)
{
        int len;
        struct bus_hdr* header;
        
        len = sizeof(struct bus_hdr);
        char buffer[len];

        header = get_bus_header(buffer);
        header->daddr = daddr;
        header->dtype = DT_NULL;
        header->stype = bus_node_type;
        header->opcode.op = BUSOP_DONE;
        header->saddr = addr;
        bus_write(bus, buffer, len);
        return 0;
}
Esempio n. 22
0
File: busio.c Progetto: joaohf/dtree
/**
 * Performs a sequence of write actions based on a file input.
 * The file input are hexadecimal numbers (given in parse_hex
 * compatible format), one per line.
 *
 * The given file descriptor is closed (even on error).
 */
int perform_file_write(const char *dev, uint32_t addr, uint32_t len, FILE *f)
{
	char s_value [S_BUFFSIZE];
	uint32_t value;

	assert(f != NULL);

	struct dtree_dev_t *d = dtree_byname(dev);
	if(d == NULL) {
		fprintf(stderr, "No device '%s' found\n", dev);
		fclose(f);
		return 1;
	}

	while (fgets(s_value, S_BUFFSIZE, f) != NULL) {
		size_t s_len = strlen(s_value);

		if (s_value[s_len - 1] == '\n') {
			s_value[s_len - 1] = '\0';
		}

		value = parse_hex(s_value, s_len);

		verbosity_printf(1, "Action: write, device: '%s', offset: '0x%08X', data: '0x%08X', len: '%d'", dev, addr, value, len);

		const dtree_addr_t base = dtree_dev_base(d);
		const dtree_addr_t high = dtree_dev_high(d);

		if(base < high) {
			if(base + addr + len > high) {
				verbosity_printf(1, "Address is out of range of the device: 0x%08X (high: 0x%08X)", base + addr, high);
				return 2;
			}
		}

		bus_write(base, addr, value, len);

		addr += len;
	}

	dtree_dev_free(d);
	fclose(f);

	return 0;
}
Esempio n. 23
0
unsigned char ds1302_read(unsigned char addr)
{
	unsigned char val;
	addr|=1;		//读操作,最低bit为1,
	CLR_RST;
	bus_nop;
	CLR_CLK;
	bus_nop;
	SET_RST;
	bus_nop;
	bus_write(addr); /* 地址,命令 */
	val = bus_read(); /* 读1Byte数据 */
	SET_CLK;
	bus_nop;
	CLR_RST;
	bus_nop; 
	return(val);
}
Esempio n. 24
0
static void
announce_wait(pid_t pid)
{
	bus_t bus;
	int i;
	t(bus_open(&bus, getenv("BUS_INIT"), BUS_WRONLY));
	for (i = 1; i < argc; i++) {
		if (!started[i]) {
			sprintf(arg, "%ji awaiting-started %s", (intmax_t)pid, argv[i]);
			t(bus_write(&bus, arg, 0));
		}
	}
	t(bus_close(&bus));
	return;

fail:
	perror("await-started");
}
Esempio n. 25
0
void ds1302_time_get_burst(unsigned char *val)
{
	unsigned char i;
	CLR_RST;
	bus_nop;
	CLR_CLK;
	bus_nop;
	SET_RST;
	bus_nop;
	bus_write(DS1302_CLKBURST_Reg+1); /* 0xbf:时钟多字节读命令 */
	for (i=8; i>0; i--)
	{
		*val = bus_read(); /* 读1Byte数据 */
		val++;
	}
	SET_CLK;
	bus_nop;
	CLR_RST;
}
Esempio n. 26
0
void handler_dev_display_write(u2_t addr, u1_t data)
{

#ifdef DEBUG
	if (trace_regs) printf("%c%x", (ADDR_DEV(addr) == ADDR_7SEG(0))? 'D':'L', addr&0xf);
#endif

	if (ADDR_DEV(addr) == ADDR_7SEG(0)) {
		dsp_7seg_write(POS(addr - ADDR_7SEG(0)), 0, data);
	} else
	if (ADDR_DEV(addr) == ADDR_LEDS(0xf)) {	// remember ADDR_LEDS() is reversed
		dsp_leds_write(0xf - (addr - ADDR_LEDS(0xf)), data);
	} else {
		bus_write(addr, data);
	}

#ifdef DEBUG
	// last digit of display has been written
	if ((display_all || deviation) && (addr == ADDR_7SEG(0xf))) {
		static char dbuf[128];
		static double dval2;
		static u4_t ddn, dskip;

		freq_record(0, REG_STR, 0, 0, 0, "D ");
		dsp_7seg_translate(dbuf, &dval2); ddn++;
		
		if (display_all || ((ddn & 0xf) == 0))
			printf("%s\n", dbuf);

		if (deviation && (fabs(dval-dval2) > 0.000001)) {
			printf("+%d %12.9f\n", ddn, dval2);
			ddn = 0;
#ifdef FREQ_DEBUG
			if (dskip > 50) reg_dump(0, reg_dump_read, NULL, reg_dump_str);
#endif
		}
		
		freq_record(0, REG_RESET, 0, 0, 0, 0);
		dskip++;
	}
#endif

}
Esempio n. 27
0
void ds1302_ram_write_burst(unsigned char *val)
{
	unsigned char i;
	DS1302_WP_DIS; //解除写保护
	CLR_RST;
	bus_nop;
	CLR_CLK;
	bus_nop;
	SET_RST;
	bus_nop;
	DS1302_RAM_BURST_WRITE; /* 0xfe:RAM多字节写命令 */
	for (i=31;i>0;i--) /*31Byte 寄存器数据 */
	{
		bus_write(*val); /* 写1Byte数据*/
		val++;
	}
	SET_CLK;
	bus_nop;
	CLR_RST;
	DS1302_WP_EN;
}
Esempio n. 28
0
/* wb_drain_all
 * @wb_t wb_t to drain
 * */
void
mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t)
{
	ARMword pa;
	wb_entry_t *wb;
	int i;

	while (wb_t->used) {
		wb = &wb_t->entrys[wb_t->last];
		pa = wb->pa;
		for (i = 0; i < wb->nb; i++) {
			//mem_write_byte (state, pa, wb->data[i]);
			bus_write(8, pa, wb->data[i]);
			//pa += WORD_SIZE;
			pa++;
		}
		wb_t->last++;
		if (wb_t->last == wb_t->num)
			wb_t->last = 0;
		wb_t->used--;
	};
}
Esempio n. 29
0
File: bus.c Progetto: uselessd/bus
/**
 * Broadcast a message on a bus
 * 
 * @param   bus      Bus information
 * @param   message  The message to write, may not be longer than
 *                   `BUS_MEMORY_SIZE` including the NUL-termination
 * @param   timeout  The time the operation shall fail with errno set
 *                   to `EAGAIN` if not completed
 * @param   clockid  The ID of the clock the `timeout` is measured with,
 *                   it most be a predictable clock
 * @return           0 on success, -1 on error
 */
int bus_write_timed(const bus_t *bus, const char *message,
		    const struct timespec *timeout, clockid_t clockid)
{
	int saved_errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	int state = 0;
#endif
	struct timespec delta;
	if (!timeout)
		return bus_write(bus, message, 0);

	DELTA;
	if (acquire_semaphore_timed(bus, X, SEM_UNDO, &delta) == -1)
		return -1;
	DELTA;
	t(zero_semaphore_timed(bus, W, 0, &delta));
	write_shared_memory(bus, message);
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(release_semaphore(bus, N, SEM_UNDO));  state++;
#endif
	t(write_semaphore(bus, Q, 0));
	t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(acquire_semaphore(bus, N, SEM_UNDO));  state--;
#endif
	t(release_semaphore(bus, X, SEM_UNDO));
	return 0;

fail:
	saved_errno = errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	if (state > 0)
		acquire_semaphore(bus, N, SEM_UNDO);
#endif
	release_semaphore(bus, X, SEM_UNDO);
	errno = saved_errno;
	return -1;

}
Esempio n. 30
0
void input_refresh(void) 
/* Reads one column of switch data each time it is called and auto-increments
   the current row
*/
{
    static uint8_t current_row = 0;
    static uint8_t stage = 0;
    static uint8_t last_data = 0;
    
    // Update row latch value
    bus_select(ROW_ADDRESS);
    bus_write(row_mirror | (0x20 << current_row));
   
    nop();
    
    // Latch row value and switch to the switch column input buffer
    bus_select(SWITCHCOL_ADDRESS);
    bus_dir_input();
    uint8_t switch_data = bus_read();
    bus_dir_output();
    bus_deselect();
    
    if (stage == 1) {	
	// Expand the switch bits into individual bytes in the input array
      uint8_t* row = &input[current_row];

      // Debouncing:
      *row = (switch_data & *row) | (switch_data & last_data) | (last_data & *row);
      
      if (++current_row == 3) 
	    current_row = 0;
    }

    stage ^= 1;

    last_data = switch_data;
}