{* * Hardware definition unit for OS-X * This version supports the rack mount Z80 cpu board 1 * * Revision history: * 940810 FrGo, last OS-X 1.0 version * * 970127 FrGo, added reset timer functions. Added global read/write * functions for inter address space data access. *} UNIT hardware; INTERFACE const ctc0 = 0; { Physical hardware addresses } ctc1 = 1; ctc2 = 2; ctc3 = 3; auxdat = $10; auxcmd = $11; ttydat = $12; ttycmd = $13; mididat = $20; midicmd = $21; linkdat = $22; linkcmd = $23; ram_select = $30; ram_data = $40; stack_base = $FD00; { Initial cpu stack base address } set_map_reg0 = $A0D3; { OUT (n),A Z80 code macros } set_map_reg1 = $A1D3; set_map_reg2 = $A2D3; set_map_reg3 = $A3D3; map0c0 = $003E; map0c1 = $013E; { Map reg1 code in logical mapping 0 } map0c2 = $093E; map0c3 = $083E; map1c1 = $0A3E; { Map reg1 code in logical mapping 1 } map1c2 = $0B3E; map1c3 = $083E; map2c1 = $0C3E; { Map reg1 code in logical mapping 2 } map2c2 = $0D3E; map2c3 = $083E; map3c1 = $0E3E; { Map reg1 code in logical mapping 3 } map3c2 = $0F3E; map3c3 = $083E; timer_vector = 0; info_sysclk = 1; info_vectors = 2; info_stack = 3; info_maps = 8; info_base0 = 9; info_size0 = 10; PROCEDURE null_int; PROCEDURE set_int(vector: int; handler: pointer); PROCEDURE set_map; PROCEDURE gread(address: int; map: char): char; PROCEDURE gwrite(address: int; map,data: char); PROCEDURE reset_watchdog; PROCEDURE reset_t0; PROCEDURE reset_t1; PROCEDURE set_timer(id,time: int; handler: pointer); PROCEDURE get_sysinfo(item: int): int; PROCEDURE _get_hostaddr(): int; PROCEDURE _get_hostname(): ^string; PROCEDURE init_hardware(); IMPLEMENTATION uses memory; const clk_freq = 6000; { System clock frequency in kHz } vector_base = $FF00; { Interupt vector table base address } reset_delay = 5000; { Reset recovery delay } out_watchdog = $90D3; wd_code0 = $FE3E; { LD A,n Z80 code macros } wd_code1 = $FF3E; map0_base = 32768; { Base address of logical mapping 0 } map0_size = 16384; { Size of logical mapping 0 } map1_base = 16384; map1_size = 32768; map2_base = 16384; map2_size = 32768; map3_base = 16384; map3_size = 32768; info : array[16] of int = ( 0, clk_freq, vector_base, stack_base, 0, 0, 0, 0, 4, map0_base, map0_size, map1_base, map1_size, map2_base, map2_size, map3_base, map3_size, ); var _map_ : char; { Current map no. } _oldmap_ : char; { Saved map no. } _oldsp_ : int; { Save SP } _smsbuf_ : array[64] of char; { Shared memory stack buffer } _smstk_ : int; { Shared memory stack top marker } PROCEDURE null_int; BEGIN inline($FB); { EI } inline($ED,$4D); { RETI } END null_int; PROCEDURE set_int(vector: int; handler: pointer); var p : ^pointer; BEGIN if vector < 128 then p := pointer(vector_base + vector); p^ := handler; end; END; PROCEDURE set_map; BEGIN inline($32,_map_); { LD (_map_),A } inline($D3,$f0); inline($E1); inline($FE,$00,$20,$0D); { MAP0 } inline(map0c1,set_map_reg1); inline(map0c2,set_map_reg2); inline(map0c3,set_map_reg3); inline($E9); inline($FE,$01,$20,$0D); { MAP1 } inline(map1c1,set_map_reg1); inline(map1c2,set_map_reg2); inline(map1c3,set_map_reg3); inline($E9); inline($FE,$02,$20,$0D); { MAP2 } inline(map2c1,set_map_reg1); inline(map2c2,set_map_reg2); inline(map2c3,set_map_reg3); inline($E9); { MAP3 } inline(map3c1,set_map_reg1); inline(map3c2,set_map_reg2); inline(map3c3,set_map_reg3); inline($E9); END set_map; {* * Read one byte from address space * Args: * A = source map no. * DE = source address * * Returns: * E = read data *} PROCEDURE _gread; BEGIN inline($F3); { _GREAD DI } inline($F5); { PUSH AF } inline($3A,_map_); { LD A,(_map_) ; Save current map no. } inline($32,_oldmap_); { LD (_oldmap_),A } inline($F1); { POP AF } inline($ED,$73,_oldsp_); { LD (_oldsp_),SP ; Save SP } inline($31,_smstk_); { LD SP,_smstk_ ; Setup stack in shared memory } inline($CD,set_map); { CALL SET_MAP } inline($1A); { LD A,(DE) } inline($5F); { LD E,A } inline($3A,_oldmap_); { LD A,(_oldmap_) } inline($CD,set_map); { CALL SET_MAP } inline($ED,$7B,_oldsp_); { LD SP,(_oldsp_) ; Restore SP } inline($FB); { EI } END; {* * Write one byte to address space * Args: * A = source map no. * C = write data * DE = source address * * Returns: * - *} PROCEDURE _gwrite; BEGIN inline($F3); { _GWRITE DI } inline($F5); { PUSH AF } inline($3A,_map_); { LD A,(_map_) ; Save current map no. } inline($32,_oldmap_); { LD (_oldmap_),A } inline($F1); { POP AF } inline($ED,$73,_oldsp_); { LD (_oldsp_),SP ; Save SP } inline($31,_smstk_); { LD SP,_smstk_ ; Setup stack in shared memory } inline($CD,set_map); { CALL SET_MAP } inline($79); { LD A,C } inline($12); { LD (DE),A } inline($3A,_oldmap_); { LD A,(_oldmap_) } inline($CD,set_map); { CALL SET_MAP } inline($ED,$7B,_oldsp_); { LD SP,(_oldsp_) ; Restore SP } inline($FB); { EI } END; PROCEDURE gread(address: int; map: char): char; BEGIN inline($FD,$5E,$04); { LD E,(IY+4) } inline($FD,$56,$05); { LD D,(IY+5) } inline($FD,$7E,$06); { LD A,(IY+6) } inline($CD,_gread); { CALL _GREAD } inline($6B); { LD L,E } END; PROCEDURE gwrite(address: int; map,data: char); BEGIN inline($FD,$5E,$04); { LD E,(IY+4) } inline($FD,$56,$05); { LD D,(IY+5) } inline($FD,$7E,$06); { LD A,(IY+6) } inline($FD,$4E,$08); { LD C,(IY+8) } inline($CD,_gwrite); { CALL _GWRITE } END; PROCEDURE reset_watchdog; BEGIN inline(wd_code0); inline(out_watchdog); inline(wd_code1); inline(out_watchdog); END; { Reset timer 0 interrupt } PROCEDURE reset_t0; BEGIN { No operation needed for Z80 CTC } END; { Reset timer 0 interrupt } PROCEDURE reset_t1; BEGIN { No operation needed for Z80 CTC } END; PROCEDURE set_timer(id,time: int; handler: pointer); BEGIN if id < 3 then if id = 2 then { Setup 16 bit timer } out(ctc0+2,#$35); { Timer mode, 1/256 prescaler, no INT } out(ctc0+2,char(time)); set_int(timer_vector+3*2,handler); out(ctc0+3,#$D5); { Counter mode, INT enable } out(ctc0+3,char(time/256)); out(ctc0,char(timer_vector and $F8)); { Set interupt vector } else { Setup 8 bit timer } set_int(timer_vector+id*2,handler); out(ctc0+id,#165); { Timer mode, 1/256 prescaler } out(ctc0+id,char(time)); out(ctc0,char(timer_vector and $F8)); { Set interupt vector } end; end; END set_timer; PROCEDURE get_sysinfo(item: int): int; BEGIN return info[item]; END get_sysinfo; PROCEDURE _get_hostaddr(): int; BEGIN return 256; END; PROCEDURE _get_hostname(): ^string; BEGIN return pointer("z80a"); END; PROCEDURE init_hardware(); var i : int; BEGIN inline($ED,$5E); { Setup vectored interupt mode (IM2) } inline($3E,$FF,$ED,$47); { Setup interupt vector table at $FF00 } { Wait for hardware to recover from reset } for i := 0 while i < reset_delay do inc(i) loop inline(out_watchdog); end loop; for i := 0 while i < 128 do inc(i) loop set_int(i,@null_int); end loop; END; BEGIN END hardware;