Atypical code examples

8-bit binary-to-ASCII

	include "p16f628.aty"

Decimal:
	byte .buff[3]
	const .ones = 2
	const .tens = 1
	const .hundreds = 0
.Convert:	// converts W to 3 ASCII digits in .buff
	.buff[.ones] = w
	w = '0', => .buff[.hundreds], => .buff[.tens]
	do
	    w = 100
	    .buff[.ones] -=> w
	    if !STATUS<C> then break
	    .buff[.ones] = w
	    ++.buff[.hundreds]
	loop
	do
	  w = 10
	  .buff[.ones] -=> w
	  if !STATUS<C> then break
	  .buff[.ones] = w
	  ++.buff[.tens]
	loop
	w = '0', +=> .buff[.ones]
	return

CRC16

Atypical version of this C code.

	include "p16f628.aty"
CRC:
	const lo = 0, hi = 1
	byte .crc[2], .temp[2]
.Init:
	clr .crc[hi]
	clr .crc[lo]
	return
.Data:
	.temp = w
	w = .crc[hi], ^ .crc[lo], ^=> .crc[hi], ^=> .crc[lo]	// swap hi and lo
	w = .temp, ^=> .crc[lo]
	w = swap .crc[lo], & 0x0f, ^=> .crc[lo]
	w = swap .crc[lo], & 0xf0, ^=> .crc[hi]
	w = swap .crc[lo], => .temp[lo], => .temp[hi]
	w = 0x0f, &=> .temp[hi]
	w = 0xf0, &=> .temp[lo]
	STATUS<C> = 0
	rol .temp[lo]
	rol .temp[hi]
	w = .temp[lo], ^=> .crc[lo]
	w = .temp[hi], ^=> .crc[hi]
	return

PS/2 keyboard communications


	include "..\p16f628.aty"

	config _WDT_OFF & _INTRC_OSC_CLKOUT & _LVP_OFF & _MCLRE_OFF

	varorg 0x20

	byte temp

	org 0
	call Keyboard.Init
	call Console.Init

	byte .b
	do
	    call Keyboard.Rx; w => .b
	    w = .b, ^ 0xaa
	loop while !STATUS<Z>

	w = 0xed; call Keyboard.Tx; call Keyboard.Rx
	w = 0x02; call Keyboard.Tx; call Keyboard.Rx	// Num Lock LED

	w = '>'; call Console.Emit
	call Console.Cr
	do
	    call Keyboard.Read
	    call Console.Emit
	loop

OutputWInHex:
	byte .b
	.b = w
	w = swap .b, & 0x0f; call .toHex; call Console.Emit
	w = .b, & 0x0f; call .toHex; call Console.Emit
return///
	w = .b; goto Console.Emit
.toHex:
	temp = w
	w = ($+4>>8), => PCLATH
	w = temp, +=> PCL
.table:	retlw { "0123456789abcdef" }
	assert ($-1>>8) == (#.table>>8)

Delay:
	byte .i, .j
	.i = w
	clr .j
	do
	    do
		nop; nop; nop
	    loop while --.j
	loop while --.i
	return

//----- Keyboard stuff ----------------------------------------------------------------
// 2003-12-28	trying keyboard
//	    --------+      +--------
//	Kbd    CLOCK| <--> |RA0  16F628
//		DATA| <--> |RA1
//	    --------+      +--------
//
//	connector (bottom view)
//	clock --o     o
//		o o o o -- +5
//	       /  |
//	    gnd	data
//
// 2003-12-28	can read scan codes
// 2003-12-30	use clock line to halt transmission while busy
// 2003-12-30	trying to implement bidirectional communication
// 2004-01-01	partial success; lots of resend messages from kbd
// 2004-01-02	trying change of timing: change bits immediately after clock goes low
//		(instead of waiting for it to go high).  Guess what?  It works!
//		Also discovered that the mapping between bits and kbd LEDS isn't
//		what one might expect.
//		to do:
//		ASCII conversion
//		interrupt-driven?

//	Communicating with an AT keyboard.
//	Keyboard.Init -- initialization stuff
//	Keyboard.Rx -- low-level routine to read a byte from the keyboard
//	Keyboard.Tx -- low-level routine to send a byte to the keyboard

	// PORTA bits
	const CLOCK = 0
	const DATA = 1
	const LED = 2


Keyboard:
	// a few useful ASCII codes:
	const .BS = 8, .CR = 13, .ESC = 27, .TAB = 9
	// some made-up codes:
	const .F1 = 0xF1, .F2 = 0xF2, .F3 = 0xF3, .F4 = 0xF4
	const .F5 = 0xF5, .F6 = 0xF6, .F7 = 0xF7, .F8 = 0xF8
	const .F9 = 0xF9, .F10 = 0xFA, .F11 = 0xFB, .F12 = 0xFC
	// useful scan codes:
	const scLSHIFT = 0x12, scRSHIFT = 0x59, scCAPSLOCK = 0x58

	byte .shift	// <1> = l.shift, <0> = r.shift
	byte .capsLock	// <1> = caps lock key pressed (for auto-repeat), <0> = caps lock on
.Init:
	w = 7, => CMCON
	clr PORTA

	STATUS<RP0> = 1
	bank 1
	TRISA<LED> = 0, <CLOCK> = 0	// <DATA> = 1 on power-up
	STATUS_1<RP0> = 0
	bank 0
	clr .shift
	clr .capsLock
	return

	byte .i, .b
.Rx:
	STATUS<RP0> = 1
	bank 1
	TRISA<CLOCK> = 1		// release clock line; keyboard can send now
	STATUS_1<RP0> = 0
	bank 0

	call .waitForClockLowThenHigh	// start bit
	w = 8, => .i
	do				// 8 data bits
	    ror .b, <7> = 0
	    call .waitForClockLow
	    if PORTA<DATA> == 1 then .b<7> = 1
	    call .waitForClockHigh
	loop while --.i
	w = .b
	call .waitForClockLowThenHigh	// parity bit
	call .waitForClockLowThenHigh	// stop bit

	STATUS<RP0> = 1
	bank 1
	TRISA<CLOCK> = 0	// tell keyboard to suspend transmission
	STATUS_1<RP0> = 0
	bank 0

	return

.Tx:	// enter with byte to send in W
	.b = w
	PORTA<DATA> = 0

	STATUS<RP0> = 1
	bank 1
	TRISA<DATA> = 0		// bring data line low
	STATUS_1<RP0> = 0
	bank 0

	STATUS<RP0> = 1
	bank 1
	TRISA<CLOCK> = 1	// release clock line; keyboard can send now
	STATUS_1<RP0> = 0
	bank 0

	call .waitForClockLow	// start bit
	byte .parity
	clr .parity
	w = 8, => .i
	do			// 8 data bits
	    w = .b, & 1		// lsb
	    STATUS<RP0> = 1
	    bank 1
	    if STATUS_1<Z> then TRISA<DATA> = 0
	    if !STATUS_1<Z> then TRISA<DATA> = 1
	    STATUS_1<RP0> = 0
	    bank 0
	    w +=> .parity
	    ror .b
	    call .waitForClockHighThenLow
	loop while --.i
	w = .parity, & 1
	STATUS<RP0> = 1
	bank 1
	if STATUS_1<Z> then TRISA<DATA> = 1
	if !STATUS_1<Z> then TRISA<DATA> = 0
	STATUS_1<RP0> = 0
	bank 0
	call .waitForClockHighThenLow	// parity bit

	STATUS<RP0> = 1
	bank 1
	TRISA<DATA> = 1		// release data line
	STATUS_1<RP0> = 0
	bank 0
	call .waitForClockHighThenLow	// stop bit
	call .waitForClockHighThenLow	// ack bit (really ought to test for valid ack)

	STATUS<RP0> = 1
	bank 1
	TRISA<CLOCK> = 0	// tell keyboard to suspend transmission
	STATUS_1<RP0> = 0
	bank 0

	return

.waitForClockLowThenHigh:
	call .waitForClockLow
	// and fall through
.waitForClockHigh:
	do
	loop while PORTA<CLOCK> != 1
	return
.waitForClockLow:
	do
	loop while PORTA<CLOCK> != 0
	return
.waitForClockHighThenLow:
	call .waitForClockHigh
	goto .waitForClockLow

.Read:
	byte .ch, .j
	do
	    call .Rx; w => .ch
	    w ^= 0xe0
	    if STATUS<Z> then		// e0 prefix
		call .Rx; w => .ch	// get next byte
		w ^= 0xf0
		if STATUS<Z> then	// key up
		    call .Rx		// ..eat following byte
		else			// key down
		    w ^= (0xf0 ^ 0x4a)	// ..keypad /
		    if STATUS<Z> then
			w = '/'; return
		    endif
		    w ^= (0x4a ^ 0x5a)	// ..keypad enter
		    if STATUS<Z> then
			w = .CR; return
		    endif
		endif
		continue
	    endif
	    w ^= (0xe0 ^ 0xe1)
	    if STATUS<Z> then		// e1 prefix: break key
		w = 7, => .j
		do
		    call .Rx		// eat 7 following bytes: 1477E1F014F077
		loop while --.j
		continue
	    endif
	    w ^= (0xe1 ^ 0xf0)
	    if STATUS<Z> then		// f0 prefix: key up
		call .Rx; w => .ch
		call .testShiftKeysUp
	    else			// key down
		w = .ch; call .testShiftKeysDown
		w ^= 0
		if !STATUS<Z> then continue
		w = .ch
		.shift = .shift
		if STATUS<Z> then
		    call .scanCodeToAsciiUnshifted
		else
		    call .scanCodeToAsciiShifted
		endif
		if .capsLock<0> then call .convertToUpperCase
		return
	    endif
	loop

.testShiftKeysDown:
	w ^= scLSHIFT
	if STATUS<Z> then
	    .shift<1> = 1
	    w = 1; return
	endif
	w ^= (scLSHIFT ^ scRSHIFT)
	if STATUS<Z> then
	    .shift<0> = 1
	    w = 1; return
	endif
	w ^= (scRSHIFT ^ scCAPSLOCK)
	if STATUS<Z> then
	    if .capsLock<1> then goto .1	// if caps lock is auto-repeating, ignore
	    w = 0xed; call Keyboard.Tx; call Keyboard.Rx	// command to set LEDs
	    if .capsLock<0> == 0 then
		.capsLock<0> = 1
		w = 0x06					// Num Lock & Caps Lock LEDs on
	    else
		.capsLock<0> = 0
		w = 0x02					// Num Lock LED (Caps Lock off)
	    endif
	    call Keyboard.Tx; call Keyboard.Rx
	    .capsLock<1> = 1
.1:	    w = 1; return
	endif
	w = 0; return

.testShiftKeysUp:
	w ^= scLSHIFT
	if STATUS<Z> then .shift<1> = 0
	w ^= (scLSHIFT ^ scRSHIFT)
	if STATUS<Z> then .shift<0> = 0
	w ^= (scRSHIFT ^ scCAPSLOCK)
	if STATUS<Z> then .capsLock<1> = 0
	return

	org ($+0xff)&(~0xff)
.scanCodeToAsciiUnshifted:
	w -= 0x84		// 0x84 items in table
	if STATUS<C> then
	    w = 0xfd
	    return
	endif
	w += 0x84, => temp
	w = ($+4>>8), => PCLATH
	w = temp, +=> PCL
.table1:retlw { 0, .F9, 0, .F5, .F3, .F1, .F2, 0, 0, .F10, .F8, .F6, .F4, .TAB, '`', 0 }
	retlw { 0, 0, 0, 0, 0, "q1", 0, 0, 0, "zsaw2", 0 }			// 10-1f
	retlw { 0, "cxde43", 0, 0, " vftr5", 0 }				// 20-2f
	retlw { 0, "nbhgy6", 0, 0, 0, "mju78", 0 }				// 30-3f
	retlw { 0, ",kio09", 0, 0, "./l;p-", 0 }				// 40-4f
	retlw { 0, 0, "'", 0, "[=", 0, 0, 0, 0, .CR, "]", 0, "\", 0, 0 }	// 50-5f
	retlw { 0, 0, 0, 0, 0, 0, .BS, 0, 0, "1", 0, "47", 0, 0, 0 }		// 60-6f
	retlw { "0.2568", .ESC, 0, .F11, "+3-*9~", .F12 }			// 70-7f
	retlw { 0, 0, 0, .F7 }							// 80-83
	assert ($-1>>8) == (#.table1>>8)

.convertToUpperCase:
	w -= 'a'
	if !STATUS<C> then
	    w += 'a'
	    return
	endif
	w -= ('z' + 1 - 'a')
	if STATUS<C> then
	    w += ('z' + 1)
	    return
	endif
	w -= ('a' - 'A' - ('z' + 1))
	return

	org ($+0xff)&(~0xff)
.scanCodeToAsciiShifted:
	w -= 0x84		// 0x84 items in table
	if STATUS<C> then
	    w = 0xfc
	    return
	endif
	w += 0x84, => temp
	w = ($+4>>8), => PCLATH
	w = temp, +=> PCL
.table2:retlw { 0, .F9, 0, .F5, .F3, .F1, .F2, 0, 0, .F10, .F8, .F6, .F4, .TAB, '~', 0 }
	retlw { 0, 0, 0, 0, 0, "Q!", 0, 0, 0, "ZSAW@", 0 }			// 10-1f
	retlw { 0, "CXDE$#", 0, 0, " VFTR%", 0 }				// 20-2f
	retlw { 0, "NBHGY^", 0, 0, 0, "MJU&*", 0 }				// 30-3f
	retlw { 0, "<KIO)(", 0, 0, ">?L:P_", 0 }				// 40-4f
	retlw { 0, 0, '"', 0, "{+", 0, 0, 0, 0, .CR, "}", 0, "|", 0, 0 }	// 50-5f
	retlw { 0, 0, 0, 0, 0, 0, .BS, 0, 0, "1", 0, "47", 0, 0, 0 }		// 60-6f
	retlw { "0.2568", .ESC, 0, .F11, "+3-*9", 0, .F12 }			// 70-7f
	retlw { 0, 0, 0, .F7 }							// 80-83
	assert ($-1>>8) == (#.table2>>8)

-------------------------------------------------- Paid Advertisement Links Below --------------------------------------------------
Checks By Phone | Verify a Check | Reorder Checks | Routing Number | Check Verification
| BIN Database |
| Recycle Food Waste Boston | Check By Phone Software Reviews | Short Term Furnished Allston | SWIFT Code Database |