program bootZ80; { Z80 Bootloader. Uses NMI, RESET, CLOCK, A15 }
uses crt; { Copyright (c) 1998, Jens Dyekjær Madsen - V16 }
const
ram = 2048; { Size of RAM - Adjust if more ram! }
frq = 4000000; { Clockfrequence }
var
lptadr: array[1..4] of word absolute 0:$408; { LPT port table}
lptbase: word;
tick: integer absolute 0:$46c; { Timer counter }
const
set0 = 12; { Swap 0 into H }
set1 = 20; { Swap 1 into H }
readv= 47; { Read (DE) to H}
load = 28; { Load DE = HL }
loadl= 74; { Set L = H }
init = 85; { Init }
prog = 108; { (DE) = H, DE++}
readbit1 = 56; { Read bit 7,H }
readbit2 = 66; { Readbit end }
boot: array[$00..$0D] of word =
( $067, {0000 00+4: LD H,A ;67 00 : 8}
$087, {0002 08+4: SET0 ADD A,A ;87 00 : 8}
$080, {0004 16+4: SET1 ADD A,B ;80 00 : 8}
$0EB, {0006 24+4: LOAD EX DE,HL ;EB 00 : 8}
$07E, {0008 32+7: LD A,(HL) ;7E 00 :11}
$0EB, {000A 43+4: READV EX DE,HL ;EB 00 : 8}
$07E, {000C 51+7: RDBIT LD A,(HL) ;7E 00 :11}
$07C, {000E 62+4: RDBIT2 LD A,H ;7C 00 : 8}
$06C, {0010 70+4: LOADL LD L,H ;6C 00 : 8}
$106, {0012 78+7: INIT LD B,1 ;06 01 : 7}
$112,$100, {0014 85+7: PGM LD (DE),A ;12 01 00 01 :17}
$113,$100); {0018 102+6: PROG INC DE ;13 01 00 01 :16}
procedure clk(n:longint; v1,v2: byte); { Toggle v1 and v2 n times (lpt)}
var
i: longint;
begin
for i:=1 to n do { Toggle n times }
begin
port[lptbase]:=v1; { Send V1 to lpt port }
port[lptbase]:=v2; { Send V2 to port }
end;
end;
procedure run(t: integer; v1,v2: byte);
begin
port[lptbase]:=v1; { Send V1 to lpt port }
t:=t+tick+1; { End time }
repeat until t-tick<0; { Wait time }
port[lptbase]:=v2; { Send V2 to lpt port }
end;
procedure cmd(n: integer); { Command on Z80 }
begin
clk(2,2,3); { reset }
clk(n+4,6,7); { Step to executed }
end;
function rdbit: byte; { Read high bit on Z80 }
begin
cmd(readbit1); { Execute command }
rdbit:=1-(port[succ(lptbase)] shr 7); { Read BUSY }
clk(readbit2-readbit1,6,7); { End command }
end;
procedure initz80; { Clear and init z80 }
var
i: integer;
osc: boolean; { External Oscilator }
procedure send(v: word); { Push data on stack }
begin
clk(longint(v)*4,6,7); { Instructions before NMI }
clk(1,5,7); { NMI }
clk(15,6,7); { 11 cycles + 4 }
end;
begin
osc:=(port[$379] and $40 = 0);
writeln('Oscilator: ',osc);
writeln('Erasing');
clk(16,2,3); { reset }
if osc then
run(((longint(ram)*49)*19)div frq,$D,7) { Fill 0067h }
else
clk(longint(ram)*49,4,7); { Fill 0067h, >49 cycles / byte }
clk(16,2,3); { reset }
send($67); { NMI }
writeln('Setup SP');
send($404-$67); { $4 = INC B, 4 cycles }
send($231-$67); { LD SP, 0402H }
if osc then
run(((longint(ram)*4+6)*19)div frq,$F,7) { Set stack pointer }
else
clk(longint(ram)*4+6,6,7); { Go, > 4*ram+6 cycles }
clk(16,2,3); { reset }
writeln('Address $1c');
clk(15*($402-$1c)DIV 2,4,7); { NMI until SP at $1C }
clk(2,6,7);
writeln('Load bootloader');
for i:=$0d downto $00 do send(boot[i]-$67); { Load bootload code }
writeln('Bootloader ok');
cmd(init); { Initialize cmd to z80 }
end;
function rdval: byte;
var
i,j: byte;
begin
j:=0; { Reset value }
for i:=1 to 8 do { Read 8 bits }
begin
j:=j+j+rdbit; { Get value }
cmd(set0); { Next bit }
end;
rdval:=j; { Return byte }
end;
procedure setval(v: byte);
var
i: byte;
begin
for i:=7 downto 0 do if (v shr i) and 1=1 then cmd(set1) else cmd(set0);
end;
procedure setadr(adr: word);
begin
setval(lo(adr));
cmd(loadl);
setval(hi(adr));
cmd(load);
end;
type
chr2 = array[1..2] of char;
const
hexd: array[0..$f] of char =
('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
hexb: array[byte] of chr2;
procedure hexinit;
var
h: chr2;
i: byte;
begin
for i:=0 to 255 do
begin
h[1]:=hexd[i shr 4];
h[2]:=hexd[i and $f];
hexb[i]:=h;
end;
end;
var
s: string;
m: word;
adr: word;
i: word;
j: byte;
k,l: word;
begin
hexinit; { Initializes hex array }
lptbase:=lptadr[1]; { Setup LPT base address}
initz80; { Clear and init z80 }
{ Check register }
setval($4a);
writeln('Check setval: ',hexb[rdval]);
{ Store message at $c0 }
s:='Hello, Z80 is on';
setadr($C0);
for i:=1 to length(s) do
begin
setval(ord(s[i]));
cmd(prog);
end;
writeln('HEX data:');
for i:=0 to $f do
begin
write(hexb[i],'0: ');
for j:=0 to $f do
begin
setadr(j+i shl 4);
cmd(readv);
write(hexb[rdval],' ');
end;
writeln;
end;
end.
               (
geocities.com/siliconvalley/peaks)                   (
geocities.com/siliconvalley)