ucl 2.0

# Copyright (c) 2006-2007 by Wayne C. Gramlich.
# All rights reserved.

# This is a boot loader that resides in high memory for
# loading programs into low memory.

# This module is using a PIC16F876A
library $pic16f876a

# The resonator is running at 16MHz:
library clock16mhz
constant microsecond = 4

library_bank 3

# The library of bus access routines for use by the PIC16F876:
library rb2bus_pic16f876

# The library of bus access routines;
library rb2bus

# This module uses a 16Mhz resonator; hence mode HS=High Speed:
configure fosc=hs, wrt=on, cpd=off

# Only the RX and TX pins on this package are used:
package pdip
    pin 1 = mclr
    pin 2 = ra0_unused
    pin 3 = ra1_unused
    pin 4 = ra2_unused
    pin 5 = ra3_unused
    pin 6 = ra4_unused
    pin 7 = ra5_unused
    pin 8 = ground
    pin 9 = osc1
    pin 10 = osc2
    pin 11 = rc0_unused
    pin 12 = rc1_unused
    pin 13 = rc2_unused
    pin 14 = rc3_unused
    pin 15 = rc4_unused
    pin 16 = rc5_unused
    pin 17 = tx
    pin 18 = rx
    pin 19 = ground2
    pin 20 = power_supply
    pin 21 = rb0_unused
    pin 22 = rb1_unused
    pin 23 = rb2_unused
    pin 24 = rb3_unused
    pin 25 = rb4_unused
    pin 26 = rb5_unused
    pin 27 = rb6_unused
    pin 28 = rb7_unused

origin 0

procedure start
    arguments_none
    returns_nothing
    return_suppress

    # We will call main, but never return; this causes the
    # compiler to set the code banks properly.
    call main()


#origin 4

#procedure interrupt
#    arguments_none
#    returns_nothing#
#
#    do_nothing

#origin 0x800
origin 0x1e00

procedure main
    arguments_none
    returns_nothing

    local address_high byte
    local address_low byte
    local command byte
    local count byte
    local id_index byte

    call rb2bus_initialize(28)

    id_index := 0

    loop_forever
	# Make sure that we have been selected:
	rb2bus_error := $true
	while rb2bus_error
	    call rb2bus_select_wait()
	    command := rb2bus_byte_get()

	switch command >> 6
	  case 0
	    # 00xx xxxx:
	    switch (command >> 3) & 7
	      case_maximum 7
	      case 0
		#: 0000 0xxx:
		switch command & 7
		  case_maximum 7
		  case 0
		    #: 0000 0000 (Set Memory Address):
		    address_high := rb2bus_byte_get()
		    address_low := rb2bus_byte_get()
		  case 1
		    #: 0000 0001 (Read Program Memory):
		    count := rb2bus_byte_get()

		    loop_exactly count
			$eeadrh := address_high
			$eeadr := address_low
		
			# Read the word:
			$eepgd := $true
			$rd := $true

			# The next two instructions are *ignored*:
			assemble
			    nop
			    nop

			# Ship the results back:
			call rb2bus_byte_put($eedath)
			call rb2bus_byte_put($eedata)

			# Increment the address
			address_low := address_low + 1
			if $z
			    address_high := address_high + 1
		    # Let them know we are done:
		    call rb2bus_byte_put(0x5c)
		  case 2
		    # 0000 0010 (Set Program Memory):
		    $eeadrh := address_high
		    $eeadr := address_low
		    $eedath := rb2bus_byte_get()
		    $eedata := rb2bus_byte_get()

		    #$eeadrh := 0
		    #$eeadr := 0x80
		    #$eedath := 0x12
		    #$eedata := 0x34

		    $eecon1 := 0
		    $eepgd := $true
		    $wren := $true
		
		    # Make sure that WRT is on in configuration word:

		    # This code must not be interrupted:
		    $gie := $false
		    $eecon2 := 0x55
		    $eecon2 := 0xaa
		    $wr := $true
		    assemble
			nop
			nop
		    $wren := $false

		    # Increment the address
		    address_low := address_low + 1
		    if $z
			address_high := address_high + 1
		    if $wrerr
			call rb2bus_byte_put(0x5b)
		    else
			call rb2bus_byte_put(0x5a)
		  case 3
		    #: 0000 0011 (Execute):
		    $pclath := address_high
		    $pcl := address_low
		  case 4
		    #: 0000 0100 (Address Low Read):
		    call rb2bus_byte_put(address_low)
		  case 5
		    #: 0000 0101 (Address High Read):
		    call rb2bus_byte_put(address_high)
	  case 3
	    # 11xx xxxx:
	    switch (command >> 3) & 7
	      case 7
		# 1111 1xxx:
		switch command & 7
		  case 5
		    # 1111 1101 (Id_next):
		    if id_index < id.size
			call rb2bus_byte_put(id[id_index])
			id_index := id_index + 1
		  case 6
		    # 1111 1110 (Id_start):
		    id_index := 0
		  case 7
		    # 1111 1111 (Deselect):
		    call rb2bus_deselect()

procedure wait
    arguments_none
    returns_nothing

    # This procedure is repeatably called whenever the software
    # is waiting for a byte to arrive from the bus.

    do_nothing

string id = "\16,0,28,3,3,14\Controller28-C\7\Gramson"




