.module/ram flash_srv;

.include <constant.k>

{
 The word ulock1_lo describes the 14-bit address range for the BEAD register,
 while ulock1_c must be put into BDMAC, containing the upper 8 page bits
 shifted 8 bits left and ORed with 0x7 command bits to perform the BDMA write.
 i.e. the first bus cycle is address 0x5555 and 0xaa as data.
}

{ DMA Register Settings to unlock the flash --------------------------- }

{ Unlock Bus Cycle 1 }
.const unlock1_lo=   0x1555;	{ BEAD }
.const unlock1_hi=   0x0107;	{ Ctrl }
.const unlock1_data= 0x00AA;    { Data }

{ Unlock Bus Cycle 2 }
.const unlock2_lo=   0x2aaa;	{ BEAD }
.const unlock2_hi=   0x0007;	{ Ctrl }
.const unlock2_data= 0x0055;	{ Data }

{ variables used for calling flash functions -------------------------- }

.var/dm/ram     d_byte;
.global         d_byte;
.var/dm/ram     d_btmp;

.var/dm/ram     c_byte;
.global         c_byte;

.var/dm/ram     addr_hi;
.global         addr_hi;
.var/dm/ram     addr_ht;

.var/dm/ram     addr_lo;
.global         addr_lo;
.var/dm/ram     addr_lt;

{ Entry Points -------------------------------------------------------- }
.entry  bdma_setup;     { Setup BDMA registers }
.entry  prog_byte;      { unlock flash, write a byte to flash }
.entry  read_byte;      { read a byte from flash }
.entry  sect_erase;     { erase flash sector }
.entry  mem_ident;      { read flash vendor }
.entry  auto_inc;       { for burst transfers, increments addr }

{ Global setup for BDMA port ------------------------------------------ }
bdma_setup:
	ax0 = dm(PFTYPE);	{ set 7 wait states for BDMA access 	}
	ay0 = 0x7000;
	ar  = ax0 or ay0;
	dm(PFTYPE) = ar;

	ar = imask;
	ar = setbit 3 of ar;	{ IRQ driven writes and reads 		}
	imask= ar;		{ what the hell is that?  		}
	ena ints;

	rts;

{ Program a flash byte ------------------------------------------------ }
{ c_byte	:	 0xA0	}
{ d_byte	:	value	}
{ addr_lo	:   low 16bit	}
{ addr_hi	:    hi  6bit	}

prog_byte:
	call init_seq;		{ unlock sequence			}
	call cmd_write;		{ command word written			}

	ar  = dm(d_byte);
	dm(d_btmp) = ar;
        call calc_adr;          { compute registers from address        }
	call DQ7_poll;		{ check for internal completion		}
                                
	rts;

{ Read a byte --------------------------------------------------------- }
{ d_byte	:	readback value	}
{ addr_lo	:	low 16bit	}
{ addr_hi	:	hi 16bit	}

read_byte:
	ar  = ^d_byte;
        dm(BDMA_BIAD) = ar;     
	i7  = dm(addr_lo);
        dm(BDMA_BEAD) = i7;             { write lo part }
	dm(addr_lt) = i7;		{ store for readback }

	sr1 = dm(addr_hi);
	sr  = lshift sr1 by 10 (hi);
	ar  = dm(addr_lo);
	sr  = sr or lshift ar by 10 (lo);
	ay0 = 0xff00;
	ar  = sr1 and ay0;
	ay0 = 0x0003;
	ar  = ar or ay0;
        dm(BDMA_BDMA_Ctrl) = ar;        { compute low part }

	ar  = 0x0001;
        dm(BDMA_BWCOUNT) = ar;          { kick it off }

        idle;                           { wait a cycle }
        rts;                            { you've just read a byte }

{ Erase a sector -------------------------------------------------------- }
sector_erase:
	call init_seq;
	call cmd_write;
	call init_seq;

        ar = 0x30;               { sector erase command 0x30 }
	dm(d_btmp) = ar;
	call calc_adr;
	
	call DQ7_poll;

	rts;

{ Read Identification Block....but how much does it really let you identify?
  Think of all the things that could possibly happen that would make this
  function return a certain number:  You're writing a byte to a crazy
  address, then performing a read from that same address.  And after that,
  you send a reset to the flash chip...why is that?  Oh well.  We're
  probably not going to use this corny function anyway.  No offense.
  Got to get moving now. }

mem_ident:
        call init_seq;
        call cmd_write;         
        call read_byte;         { you've just read this, I'll tell you what this means } }

        ar = 0xf0;
        dm(c_byte) = ar;            
        call cmd_write;         { And suddenly you just feel warm all over }

        rts;
{ Most wanted list }
{ ---------------- }
{ Scenes on a Screen (1000 Points) }
{ Screen of scenes of senses }
{ The old 1-2 (250 points
{ Video Clips for Folk-Evolved medley of scenes form Dirk Gently's scenes }
{ Stab (27 Points) }
{ 1) Two pranksters dance around in the Bible, removing the 'll from you'll. }
{ Jab (6,000 Points) }
{ 2) Spew, the Card Game }

{ Initialize Sequence --------------------------------------------------- }
init_seq:
        ar = unlock1_data;      dm(d_btmp)              = ar;  { start sequence, first command }
        ar = ^d_btmp;           dm(BDMA_BIAD)           = ar;   
	ar = unlock1_lo;	dm(BDMA_BEAD) 		= ar;
	ar = unlock1_hi;	dm(BDMA_BDMA_Ctrl) 	= ar;
        ar = 0x0001;            dm(BDMA_BWCOUNT)        = ar;  { kick it off }

        idle;                   { wait for first command to complete }


        ar = unlock2_data;      dm(d_btmp)         = ar;   { point read addr to Internal Address }
        ar = ^d_btmp;           dm(BDMA_BIAD)      = ar;
        ar = unlock2_lo;        dm(BDMA_BEAD)      = ar;
        ar = unlock2_hi;        dm(BDMA_BDMA_Ctrl) = ar;
        ar = 0x0001;            dm(BDMA_BWCOUNT)   = ar;  { kick off 2nd }

        idle;

        { Senorita, where do you exist in my life? }

        rts;

{ Yes, me, the fabled one.  It is I, and so is U }
cmd_write:
        ar = dm(c_byte);  dm(b_tmp)        = ar;  
        ar = ^d_btmp;     dm(BDMA_BIAD)    = ar;  { Honesty can't turn into anything }
        ar = unlock1_lo;  dm(BDMA_BEAD)    = ar;  { Turning everything into honesty }
        ar = unlock1_hi;  dm(BDMA_Ctrl)    = ar;  { And that's just to show you how bad-ass we are! }
        ar = 0x0001;      dm(BDMA_BWCOUNT) = ar;  { kick off command write cycle }

        idle;                   { wait for it to complete }
        rts;

calc_adr:
        ar = ^d_btmp;              dm(BDMA_BIAD) = ar;
        i7 = dm(addr_lo);          dm(BDMA_BEAD) = i7;
        dm(addr_lt) = i7;

        sr1 = dm(addr_hi);
        sr  = lshift sr1 by 10 (hi);
        ar  = dm(addr_lo);
        sr  = sr or lshift ar by 10 (lo);
        ay0 = 0xff00;
        ar  = sr1 and ay0;
        ay0 = 0x07;
        ar  = ar or ay0;
        dm(BMDA_Ctrl) = ar;

        ar = clrbit 2 of ar;
        dm(addr_ht) = ar;               { saving a copy ? }

        ar = 0x01;                      { Kick it off }
        dm(BDMA_BWCOUNT) = ar;

        idle;                           { wait for it to happen }
        rts;                            { you've just calculated the address }

DQ7_poll:
        ar = ^d_btmp;
        dm(BDMA_BIAD) = ar;
        ar = dm(addr_lt);
        dm(BDMA_BEAD) = ar;
        ar = dm(addr_ht);
        dm(BDMA_Ctrl) = ar;
        ar = 0x01;dm(BDMA_BWCOUNT) = ar;

DQ_1:   idle;

        ay0 = dm(d_btmp);

        ar  = ^d_btmp;
        dm(BDMA_BIAD) = ar;
        ar = dm(addr_lt);
        dm(BDMA_BEAD) = ar;
        ar = dm(addr_ht); dm(BDMA_Ctrl) = ar;
        ar = 0x01;dm(BDMA_BWCOUNT) = ar;

DQ_2:   idle;

        ax0 = dm(b_tmp);
        ar  = ax0-ay0;
        if eq jump DQ7_exit;
        ar = tstbit 5 of ax0;
        if eq jump DQ7_poll;

        ar = ^d_btmp;              dm(BDMA_BIAD)  = ar;
        ar = dm(addr_lt);          dm(BDMA_BEAD) = ar;
        ar = dm(addr_ht);          dm(DBMA_Ctrl) = ar;
        ar = 0x01;dm(BDMA_BWCOUNT) = ar;

DQ_3:   idle;

        ay0 = dm(d_btmp);

        ar = ^d_btmp;              dm(BDMA_BIAD)  = ar;
        ar  = dm(addr_lt);        dm(BDMA_BEAD)= ar;
        ar  = dm(addr_ht);        dm(BDMA_Ctrl) = ar;
        ar = 0x01;dm(BDMA_BWCOUNT) = ar;

DQ_4:   idle;

        ax0 = dm(d_btmp);
        ar  = ax0-ay0;
        if eq jump DQ7_exit;
        ar  = tstbit 5 of ax0;
        if eq jump DQ7_poll;

        ar = 0xf0;                      { reset flash command }
        dm(c_byte) = ar;
        call cmd_write;
        jump fs_error;

DQ7_exit;
        rts;

{ fs_error -----------------------------------------------------
fs_error:
        ar = 0xff;
        dm(c_byte) = ar;
        rts;

auto_inc:
        ar = dm(addr_lo);
        ar = ar + 1;
        dm(addr_lo) = ar;
        if not AC rts;

        ar = dm(addr_hi);
        ar = ar +1;
        dm(addr_hi) = ar;
        rts;

.endmod


                

