title '80186 rom' include system.lib include sysdat.lib include 186regs.lib verh equ '1' verm equ '0' verl equ '0' ;author - njgr - v 1.00d ;yet another version 1.00 - note version letter is at end of version string ;but not printed out ;change record ;16/1/86 V 0.11 - njgr ;osword read line implemented ;escape flag added (but position not fixed) ;17/1/86 V 0.12 - njgr ;*run implemented ;error handling improved ;17/1/86 V 0.14 ;*help interface added ;17/1/86 V 0.15 ;interrupts re-enabled in r4 error routine after writing out error message ;a few versions later ... ;28/4/86 0.86 ;xfer changed to tfer so it doesn't clash with adt ;18/6/86 1.00 ;Tube drq bug fixed ;The following sequence of events causes spurious drq's to be generated with ;catastrophic results if the dma channel is enabled ;Claim tube ;Set up for host to parasite transfer (i.e. type 1) ;write byte to tube ;Set up for parasite to host transfer (i.e. type 0) ;delay (i.e. 24 us) ;Read byte from tube ;Release tube ;The initial write will work correctly and generate a drq pulse but while ;R1STAT is being updated on the host for the p to h operation the drq line ;goes high causing the dma channel to corrupt parasite memory (if it is ;enabled) starting from the byte after the transfer address for host write ;operation. On the host R1STAT is updated immediately after the 4 byte ;transfer address is sent hence the solution in software is to ensure that ;the dma channel is not enabled while R1STAT is being written to on the ;host. Since R1STAT is updated after sending the address it should be ;sufficient to disable the dma channel before the transfer address is removed ;on the parasite side but is probably safer to disable it as soon as possible ;i.e. on entry to routine r4_protocol which handles block transfers ;note above tube operation is legal but is very rarely used as filing systems ;have separate routines for reading and writing data which ensures that the ;tube is released before changing the direction of transfer ;note also that this problem does not affect nmi transfers i.e. no spurious ;nmi pulses are generated by updating R1STAT ; to be implemented ; ----------------- ;fix segment wrap round in i_r1_r4 ;------------------ ;testing - use cntrl t break mode a%=121:x%=&a3:call osbyte x<0 if pressed ;memory - r/w and refresh ;dma ;timers ;tube ;cpu ;checksum ;------------------ ;read_host / write_host - use es:[di] to point to parasite address ;don't use osfind to search for :0.$.dosboot (too slow) trap error instead ;in cli set up ds in cli_run not at start ;---------------------- ;monitor commands ;compare blocks of memory (b) ;fill blocks of memory (f) ;move memory (mm) ;search memory for string (sr) ;change syntax for xfer ; (:) | () (|) ;where end address can be replaced by + ;set,dump should work with io addresses - *set - whole screen ? ;---------------------------- ;change name of hard disk partition to dos from msdos ;check registers saved in all os routines ;put os call addresses at fffef down ;use 00600 down for indirection vectors ;256 byte dma transfers ;write message before copying to ram (for testing - ps whinge) ; implemented ; ----------- ;*set up int1 to be edge triggered - ij's sordid ibm s/w bodge - done by ij ;*oscli should use ds:[bx] to point to command line ;*exec_ptr initialisation fails with new pcs1 board ;*dos command - check for shadow - disable escape and run dosboot ;*set memory ;*transfer memory to/from host i.e. implement osword &ff ;*use error mechanism to write out errors ;*jump to address ;*change timer to 16 us for 10 Mhz cpu ;*error mechanism (int 0ffh ?) ;*brkvec ;*evtvec ;*faultp ;*flags not set in os interrupt routines i.e. int preserves flags ;put 1 wait state in for ucs (roms too slow) ;*take out key press to enter monitor ;*put in ibm char set ;*note code needs to be allocated for 80186 ;*check code in *run for language and processor type ;*byte 6 of sways rom format contains processor type information i.e. ;*286 compatibility (i.e. rom works with both) ;*change boot16 to dosboot ;*select adfs ;*search for :0.$.dosboot then :4.$.dosboot ;*osbput ;*osbget ;*osargs ;*osfile ;*osasci ;**run ;*select mode 3 ;*disable shadow ;*osword read line ;*escape flag ;*don't disable shadow on issue 7 (nb 186 board may be used with issue 7,10) ; bugs ; ---- ;mos bug ??? ;when prb mos is in cli mode - mos sways rom is copied across on break ;hence pointer is modified causing dos boot to be attempted ;i.e. like cntrl break ;0.44 ;if dosboot loaded with *lo. dosboot *go 4000 fails (*go 0400:0000 ok) ;nb this is because dosboot assumes cs = 0400h on entry i.e. not a *go bug ;0.63 ;if no language copied over then tube code is copied ;*go space passed on ;*s space passed on ;*xferq not passed on ;*go 0 :8000 fails ;0.66j ;*s fails in 40 column modes ;*help mon fails on 286 as rom segment used for help messages ;the rom is located from c000:0 and is reflected in 16 K bits up to the ;top of memory ;at present the top of memory map looks like ;ffc00 - ffc49 186 initialisation code ;ffff0 reset vector ;but need to implement following ;ffa6e - ffe6e ibm character set ;fffbe - fffe9 os jump table i.e. efff:ffce - efff:fff9 ;misc bits ;processor type byte table ;b3 b2 b1 b0 ;0 0 0 0 6502 basic ;0 0 0 1 turbo 6502 basic ;0 0 1 0 6502 not basic ;0 0 1 1 68000 ;0 1 0 0 - ;0 1 0 1 - ;0 1 1 0 - ;0 1 1 1 - ;1 0 0 0 Z80 ;1 0 0 1 32016 ;1 0 1 0 - ;1 0 1 1 80186 ;1 1 0 0 80286 ;1 1 0 1 ARM ;1 1 1 0 - ;1 1 1 1 - ;prb read sensitive locations fee3,feeb,fef3,fefb ;tube equates tube_base equ 080h r1stat equ tube_base+0 ; console i/o r1data equ tube_base+2 r2stat equ tube_base+4 ; console i/o r2data equ tube_base+6 r3stat equ tube_base+8 ; NMI port r3data equ tube_base+10 r4stat equ tube_base+12 ; interrupts, data transfer, NMI setup r4data equ tube_base+14 ; tube control equates rdchno equ 0 clino equ 2 sbytno equ 4 byteno equ 6 wordno equ 8 rdlnno equ 0ah argsno equ 0ch bgetno equ 0eh bputno equ 10h findno equ 12h fileno equ 14h gbpbno equ 16h ;some osbyte numbers kbd_scan equ 122 romreq equ 143 ;some osbyte parameters read_reset_type equ 253 rw_shadow equ 239 read_cursor equ 134 shadow_select equ 114 shadow_off equ 1 initfs equ 18 m_key_no equ 101 t_key_no equ 35 ;some osword numbers readio equ 5 writeio equ 6 readstatus equ 070h transfer equ 0fah ;some osword parameters osword_fa_send_params equ 0eh ;some filing system numbers adfs equ 8 dfs equ 4 nfs equ 5 ;some vdu codes mode equ 22 event_keyboard equ 10 event_timer equ 4 ;some timer stuff count_8_MHz equ 20h count_10_MHz equ 28h count_12_5_MHz equ 32h count equ count_10_MHz ;some misc bits code_186 equ 0bh rom_size equ 04000h user_vector equ 0200h tube_code_start equ 02500h ram_copy equ 0f4h rom_latch equ 0fe30h block_read equ 1 block_write equ 0 q_block_read equ 7 q_block_write equ 6 ;some equates for *set hex_field_start equ 11 hex_field_end equ 56 text_field_start equ 58 text_field_end equ 73 findv equ word ptr .05d4h gbpbv equ word ptr .05d8h bputv equ word ptr .05dch bgetv equ word ptr .05e0h argsv equ word ptr .05e4h filev equ word ptr .05e8h rdchv equ word ptr .05ech wrchv equ word ptr .05f0h wordv equ word ptr .05f4h bytev equ word ptr .05f8h cliv equ word ptr .05fch rom_seg equ 0f000h os_table_base equ 0580h cseg 0 dw 0,0 ;0 dw 0,0 ;1 dw 0,0 ;2 dw 0,0 ;3 dw 0,0 ;4 dw 0,0 ;5 dw 0,0 ;6 dw 0,0 ;7 dw 0,0 ;8 dw 0,0 ;9 dw 0,0 ;10 dw 0,0 ;11 dw i_r1r4,rom_seg ;12 dw 0,0 ;13 dw 0,0 ;14 dw 0,0 ;15 dw 0,0 ;16 dw 0,0 ;17 dw 0,0 ;18 dw 0,0 ;19 org 040h*4 dw osfind_int,rom_seg ;40 dw osgbpb_int,rom_seg ;41 dw osbput_int,rom_seg ;42 dw osbget_int,rom_seg ;43 dw osargs_int,rom_seg ;44 dw osfile_int,rom_seg ;45 dw osrdch_int,rom_seg ;46 dw osasci_int,rom_seg ;47 dw osnewl_int,rom_seg ;48 dw oswrch_int,rom_seg ;49 dw osword_int,rom_seg ;4a dw osbyte_int,rom_seg ;4b dw oscli_int,rom_seg ;4c dw 0,0 ;4d dw 0,0 ;4e dw brk,rom_seg ;4f org 0413h ;now some ibm rom bios data - you know it makes sense memory_size dw 0 ;ram memory size in kb ; org os_table_base ;vector_table dw find,rom_seg ; dw gbpb,rom_seg ; dw bput,rom_seg ; dw bget,rom_seg ; dw args,rom_seg ; dw file,rom_seg ; dw rdch,rom_seg ; dw wrch,rom_seg ; dw word,rom_seg ; dw byte,rom_seg ; dw cli,rom_seg org 0500h rw 40 monitor_tos rw 0 buffer equ $ error_buffer rb 80 buffer_end equ $ i_r1r4_off dw 0cccch ;59e i_r1r4_seg dw 0cccch ;5a0 exec_off dw 0 ;5a2 exec_seg dw 0 ;5a4 first rb 4 first_flag db 0,0 rom_base equ offset $ i_r1r4_type db 0ffh ;5a6 i_r1r4_claimer db 0ffh ;5a7 i_r1r4_dma_busy db false ;5a8 cli_flag db 0 ;5a9 reset_type db 0 ;5aa db 0 ;5ab copy_ptr dw offset copyright ;5ac dw rom_seg ;5ae ;now some variables for the dump routine start_address dw 0 ;5b0 end_address dw 0 ;5b2 seg_address dw 0 ;5b4 in_address dw 0 ;5b6 temp dw 0 ;5b8 display_byte db 0 ;5ba buftbl dw buffer db 80,32,255 rwcb dw 0,0 db 0 block db osword_fa_send_params,1 dw 0,0 dw 0,0 dw 0 db 0 current_rom db 0 rom_number db 0 syntax db 0 ;used in get_params pass_on db 0 top_bit db 0 ;used in search org 05f2h escflg db 0 db 0 fault_off dw 0 fault_seg dw 0 brk_off dw offset default_brk brk_seg dw seg default_brk event_off dw 0 event_seg dw 0 org 0a00h code_start: in al,50h ;this switches out rom on 286 mov ax,cs ;set up 8080 model mov ds,ax mov es,ax mov ss,ax mov sp,offset i_r1r4_tos ;set up stack push sp pop ax cmp ax,sp jnz leave_int_table push ds sub ax,ax mov ds,ax ;ds=0 mov bx,033h ;use i_r1r4 in ram mov [bx],al mov bx,offset copy_ptr+3 mov [bx],al mov bx,0103h mov cx,16 ;16 interrupts to do reset_int_segs: mov [bx],al add bx,4 loop reset_int_segs pop ds leave_int_table: sti ;enable interrupts mov al,ds:byte ptr first_flag or al,al jnz first_time mov bx,ds:exec_off mov cx,ds:exec_seg jmps not_first first_time: mov bx,offset monitor mov ds:exec_off,bx mov cx,seg monitor mov ds:exec_seg,cx not_first: mov ds:i_r1r4_off,bx mov ds:i_r1r4_seg,cx ; start up sequence ; ----------------- ;Use OSWRCH to write out a startup message terminated by zero byte (which must ;be sent by OSWRCH) ;Wait for data in R2DATA (65O2 response) ;During this wait a load may occur from the host using R3/R4 block transfer ;mechanism ;IF byte=&80 THEN code has been loaded at (PTR) from 6502 i.e. high priority ;language rom has been copied across from 6502 call init_memory ;get memory size mov bx,offset startup ;write first bit of startup message call smsg ;don't send terminating zero push sp ;get processor type pop ax cmp ax,sp jz its_a_286 mov ax,186 ;write out processor type jmps its_a_186 its_a_286: mov ax,286 its_a_186: call pdec mov al,' ' call wrch mov ax,num_kb ;now write out memory size call pdec mov bx,offset st0 ;and rest of message call pmsg ;send terminating zero this time call read_r2 ;wait for 6502 response ;now check kbd for 't' - do system test mov al,kbd_scan ;scan kbd for t call sbyte cmp bl,t_key_no ;is t being pressed? jz test_wanted ;yes, so do system test no_test: mov al,read_reset_type ;read reset type mov bx,0ff00h ;bl=0 => soft bl=1 => power up call sbyte ;bl=2 => hard and bl,bl ;soft reset? jnz no_monitor ;no, so don't enter monitor call copy_tube_code ;copy tube code jmp monitor ;and enter monitor ;ok no 't' pressed but if its the first time that the 186 has been ;started up then do a system test anyway no_monitor: mov al,ds:byte ptr first_flag or al,al jz no_first_test test_wanted: call system_test no_first_test: mov al,read_reset_type ;read reset type mov bx,0ff00h ;bl=0 => soft bl=1 => power up call sbyte ;bl=2 => hard mov reset_type,bl call copy_tube_code ;check first time flag and do more tests if set jmp runit system_test: mov cx,7 ;number of 64 k segments left to do mov ax,01000h ;start at 1000:0 next_segment: push cx mov ds,ax mov es,ax call memory_test mov ax,ds add ax,01000h pop cx ;get count back loop next_segment ;and test next 64k block call test_timer call test_refresh call test_dma ret ;entry ds,es point to segment to test memory_test: mov ax,0aaaah ;set up test pattern check_next_bit: mov cx,08000h ;do 64k i.e. 32k words mov bx,cx ;save count cld ;forward direction mov dx,ax ;save test pattern sub di,di ;di=0 rep stosw ;es:[di] <- ax ; di = di + 2 ;on exit from rep di=cx=0 mov cx,bx ;recover count sub si,si check_next_word: lodsw ;ax <- ds:[si] ; si = si + 2 xor ax,dx ;test pattern as written ? jnz memory_fault ;type 0 error at si-2 loop check_next_word mov ax,dx ;recover ax cmp ax,05555h jz do_address_test mov ax,05555h jmps check_next_bit ;registers now set up as follows ;di = 0 , bx = 08000h , es = ds = 0 do_address_test: sub ax,ax mov cx,bx ;clear memory for next test rep stosw mov dl,1 ;set up error type sub si,si ;use si for address check_address_lines_joined: mov di,si ;save si mov ax,-1 ;set up test pattern mov [si],al ;write test byte to first byte of block cmp si,0 jnz next_check inc si ;si=1 jmps check_address_low_or_high next_check: mov dl,3 ;set up error type shl si,1 check_address_low_or_high: mov al,[si] cmp al,0 jnz address_problem ;type 1 error at 0/si or type 2 at di/si shl si,1 jnz check_address_low_or_high mov si,di ;recover start of block or si,si jnz not_0 inc si jmps check_address_lines_joined not_0: shl si,1 jns check_address_lines_joined ret memory_fault: sub dl,dl dec si dec si jmps mem_error address_problem: cmp al,ah jnz mem_error inc dl mem_error: push si push di sub ax,ax ;reset ds mov ds,ax mov bx,offset error_msg call pmsg mov al,dl add al,'0' call wrch mov al,'/' call wrch pop di pop si or dl,dl jz type_0 mov bx,di call hexword mov al,'/' call wrch type_0: mov bx,si call hexword cli hlt error_msg db cr,lf,'Ram fault type ',0 test_timer: ret test_refresh: ret test_dma: ret ;no key pressed so load and execute the boot file boot: mov al,0 ;*fx0,1 - read machine type mov bl,1 call sbyte mov issue,bl ;and save it ;if os number returned is < 2 => no shadow memory else shadow available cmp bl,2 jc shadow_not_on ;ok we've got shadow memory in the m/c so may have do disable shadow mode mov al,rw_shadow ;*fx239,0,255 - read shadow state mov bx,0ff00h call sbyte ;bl=0 => shadow enabled or bl,bl jnz shadow_not_on ;shadows enabled so better disable it mov al,shadow_select ;*fx114,1 - disable shadow mov bl,shadow_off call sbyte shadow_not_on: call select_fadfs ;have we got adfs - select as fadfs? jz got_adfs ;panic !!!!!!!! - no adfs in the machine - unlikely scenario this but if the ;internal coproc bodge board idea gets off the ground then all sorts of hideous ;possibilities arise - punters with issue 3 beebs with 0.90 dfs and 8271's trying ;to use a 186 - i'm feeling faint just thinking about it panic db 0cdh,04fh,0ffh,'Cannot boot DOS - ADFS not present',cr,lf,0 ;IF winnie present ;THEN IF :0.$.dosboot present ; THEN load and run it ; ELSE IF :4.$.dosboot present ; THEN load and run it ; ELSE moan at punter ;ELSE IF :4.$.dosboot present ; THEN load and run it ; ELSE moan at punter got_adfs: mov bx,offset mount_drive0 ;do *dir :0 call cli call check_winnie jz no_winnie mov al,040h ;ok we've got adfs but have we got boot mov bx,offset drive ;file :0.$.dosboot ? call find ;well lets try and open it or al,al ;al=0 => file not present jnz got_boot_file ;rats! no boot file on winnie - try floppy no_winnie: mov bx,offset mount_drive4 ;*dir :4 call cli mov al,040h mov bx,offset drive call find or al,al jnz got_boot_file ;pah ! no boot file there either - moan at the punter moan db 0cdh,04fh,0ffh,'Cannot boot DOS - boot file not found',cr,lf,0 dos_re_boot: got_boot_file: mov bx,offset mode3 call pmsg ;vdu 22,3 - select mode 3 ; mov al,229 ;*fx229,1 - disable escape ; mov bx,1 ; call sbyte mov bx,offset close ;close file call cli mov bx,offset boot_file ;load file call cli ;if we get here we must have loaded boot file ok (could still contain garbage ;of course - should we do a test ?) so set up exec_ptr to reload dos on break ;assuming things like shadow disabled and boot file present - things makes ;rebooting rather less ponderous as adfs takes an inordinate length of time ;searching for a file on floppies - of course if the punter has replaced his ;boot disc then he will get an adfs disc error mov ax,offset dos_re_boot mov ds:exec_off,ax mov ax,seg dos_re_boot mov ds:exec_seg,ax db 0eah ;and jump to start address dw 0,0400h monitor: mov ax,cs ;set up segment registers mov es,ax sub ax,ax ;ds=0 to access system data mov ds,ax mov ss,ax mov sp,offset monitor_tos ;reset stack mov ax,offset monitor ;set up exec pointer mov ds:exec_off,ax mov ax,seg monitor mov ds:exec_seg,ax mov ax,offset default_brk mov ds:brk_off,ax mov ax,seg default_brk mov ds:brk_seg,ax mov al,229 ;*fx229,0 - re-enable escape for mov bx,0 ;monitor call sbyte comm: mov al,'*' call wrch mov bx,offset buftbl mov al,0 call sword jc escape mov bx,offset buffer call cli jmps comm esc_nl: call newl escape: mov al,07eh call sbyte esc_msg db 0cdh,04fh,011h,'Escape',0 ;some variables for init_memory memory_top dw 0 lo_mem_top dw -1 num_mmkb dw 1024 num_kb dw -1 neil db 'neil' neilck equ word ptr 'n'+'e'+'i'+'l' status dw 0 issue db 0 mount_drive0 db 'dir :0',cr mount_drive4 db 'dir :4',cr close db 'close',cr mode3 db 22,3,0 response db 0 startup db cr,lf,'Acorn TUBE 80',0 st0 db 'K',cr,lf,cr,lf,0 boot_file db 'load ' drive db '$.dosboot 04000000',cr fadfs_mess db 'fadfs',cr ;entry none ;exit al = fs ;used ax ;saved none get_fs: sub ax,ax jmp args select_fadfs: mov bx,offset fadfs_mess ;do a *fadfs call cli call get_fs cmp al,adfs ;did we succeed? ret ;entry bh filing system number ;exit z => fs selected ; nz => fs not selected (i.e. not present) ;used al , bx ;saved bx select_fs: push bx mov al,romreq ;*fx143,18,(bh) mov bl,initfs call sbyte call get_fs ;get current fs type pop bx cmp al,bh ;set flags ret ;/***************************************************************/ ;/* */ ;/* Memory initialization */ ;/* */ ;/* Perform a memory test to find amount of memory */ ;/* installed in machine (even on the A300/A310). */ ;/***************************************************************/ init_memory: ;------------ pushf ; save flag state push es ; and UDA cld cli ; minimise memory useage during sizing mov num_mmkb, 1024 ; max 1024 KB mov memory_top, 0ffffh ; never use top paragraph mov ax, 64*64 ; top of 1st 128k block push ds mov ds, ax mov cx, word ptr .0fffch ; save the bits of the system mov dx, word ptr .0fffeh ; we may corrupt, and pray pop ds ; we don't crash things... mov ax, (1024-64)*64 ; point to upper half of 128 Kb bank init_m1: mov es, ax ; point to segment mov di, 0fffch ; point last dword stosw ; write test pattern not ax ; invert it stosw ; store the invert of the test pattern not ax ; and restore ax sub ax, 128*64 ; next 128 Kb block jnc init_m1 ; check one megabyte mov ax, (1024-64)*64 ; point to 1st bank written init_m2: mov es, ax ; point to segment mov di, 0fffch ; last dword scasw ; same pattern as written? jne init_m3 ; no, try next bank not ax ; invert the pattern scasw ; test inverted pattern as written? je init_m4 ; yes, get out of here not ax ; restore ax init_m3: sub memory_top, 128*64 ; count another 128 Kb sub num_mmkb, 128 sub ax, 128*64 ; else get to next bank jnc init_m2 ; loop until no memory mov memory_top, 0 ; really none init_m4: mov ax, memory_top mov lo_mem_top, ax ; save for SETUP mov ax, num_mmkb mov num_kb, ax ; and for startup msg mov memory_size,ax ;and for dos to use mov ax, 64*64 ; top of 1st 128k block push ds mov ds, ax mov word ptr .0fffch, cx ; restore the bits of the system mov word ptr .0fffeh, dx ; we are have corrupted pop ds ; and pray we didn't crash things... pop es ; restore UDA popf ; restore int state ret pdec: ;----- ; print the value in AX in decimal and ax, ax jz pdec2 mov dx, 0 mov bx, 10 ; divide by 10 div bx push dx call pdec ; print out any higher digits pop cx add cl, '0' ; make ASCII call conout ; and print least significant digit pdec2: ret conout: mov al,cl jmp wrch ;entry none ;exit z => no winnie ; nz => winnie ;used al , bx ;saved none copy_tube_code: cli push ds mov ax,0 mov ds,ax mov bx,tube_code_start push bx mov si,offset oswdfa mov cx,oswdfa_end-offset oswdfa call write_host ;now read user vector in host mov bx,user_vector mov si,offset temp mov cx,2 call read_host ;and write to tube_code_start+3 pop bx add bx,3 mov si,offset temp mov cx,2 call write_host ;now update user vector to point to osword &fa mov bx,tube_code_start mov ds:temp,bx mov bx,user_vector mov si,offset temp mov cx,2 call write_host pop ds sti ret ;entry bx host adress ; ds parasite segment ; si parasite offset ; cx length of transfer read_host: mov ds:rwcb,bx push bx mov bx,offset rwcb mov al,readio call sword mov al,byte ptr rwcb+4 mov [si],al inc si pop bx inc bx loop read_host ret write_host: mov ds:rwcb,bx mov al,[si] mov byte ptr rwcb+4,al push bx mov bx,offset rwcb mov al,writeio call sword inc si pop bx inc bx loop write_host ret ;entry bx host address ; es parasite segment ; di parasite offset ; cx length ; al operation type q_read_write: push ds push bx push ax sub ax,ax mov ds,ax mov ds:word ptr block,0100h+osword_fa_send_params mov ds:word ptr block+2,bx mov ds:word ptr block+6,di mov ax,es mov ds:word ptr block+8,ax mov ds:word ptr block+10,cx pop ax mov ds:byte ptr block+12,al mov bx,offset block mov al,0fah call sword pop bx pop ds ret oswdfa db 018h,090h,002h,010h,0E3h,0C9h,0FAh,0F0h db 003h,06Ch,003h,025h,086h,070h,084h,071h db 048h,0A9h,0FBh,0A2h,000h,0A0h,0FFh,020h db 0F4h,0FFh,086h,073h,0ADh,034h,0FEh,048h db 0A9h,0C7h,020h,006h,004h,090h,0F9h,0A0h db 000h,0B1h,070h,0C9h,00Dh,008h,0A5h,0F4h db 085h,072h,0A0h,00Dh,0B1h,070h,0AAh,0A0h db 002h,0B1h,070h,085h,074h,0C8h,0B1h,070h db 085h,075h,028h,0F0h,040h,08Ah,048h,029h db 040h,0D0h,013h,08Ah,029h,020h,0D0h,004h db 0A2h,000h,0F0h,002h,0A2h,001h,0A9h,06Ch db 020h,0F4h,0FFh,04Ch,077h,025h,0A9h,084h db 020h,0F4h,0FFh,0C0h,080h,0D0h,008h,0A9h db 001h,0C5h,073h,0D0h,0E7h,0F0h,0E1h,0A9h db 002h,0C5h,073h,0D0h,0DBh,0F0h,0DDh,068h db 0AAh,029h,010h,0D0h,008h,08Ah,029h,00Fh db 085h,0F4h,08Dh,030h,0FEh,0A0h,00Ah,0B1h db 070h,085h,077h,0C8h,0B1h,070h,085h,076h db 005h,077h,0D0h,002h,0F0h,06Eh,0A5h,077h db 0F0h,002h,0E6h,076h,0C8h,0B1h,070h,048h db 0A5h,077h,0F0h,011h,0A5h,076h,0C9h,001h db 0D0h,00Bh,068h,048h,0C9h,006h,090h,005h db 068h,038h,0E9h,006h,048h,0A5h,070h,018h db 069h,006h,0AAh,0A9h,000h,065h,071h,0A8h db 068h,048h,020h,006h,004h,0A6h,077h,068h db 0A0h,000h,0C9h,000h,0F0h,01Eh,0C9h,001h db 0F0h,035h,0C9h,002h,0F0h,049h,0C9h,003h db 0F0h,070h,0C9h,006h,0F0h,008h,0C9h,007h db 0F0h,007h,0A9h,000h,0F0h,01Eh,04Ch,075h db 026h,04Ch,0A3h,026h,020h,0F4h,026h,0ADh db 0E5h,0FEh,091h,074h,020h,0F4h,026h,0E6h db 074h,0D0h,002h,0E6h,075h,0CAh,0D0h,0EFh db 0C6h,076h,0D0h,0EBh,04Ch,0DAh,026h,0B1h db 074h,08Dh,0E5h,0FEh,020h,0F4h,026h,0E6h db 074h,0D0h,002h,0E6h,075h,0CAh,0D0h,0EFh db 0C6h,076h,0D0h,0EBh,04Ch,0DAh,026h,020h db 0F4h,026h,0ADh,0E5h,0FEh,091h,074h,0E6h db 074h,0D0h,002h,0E6h,075h,0EAh,0EAh,0ADh db 0E5h,0FEh,091h,074h,0E6h,074h,0D0h,002h db 0E6h,075h,020h,0F3h,026h,0EAh,0EAh,0CAh db 0CAh,0D0h,0DFh,0C6h,076h,0D0h,0DBh,04Ch db 0DAh,026h,0B1h,074h,08Dh,0E5h,0FEh,0E6h db 074h,0F0h,003h,0EAh,0D0h,002h,0E6h,075h db 0A5h,073h,0B1h,074h,08Dh,0E5h,0FEh,0E6h db 074h,0F0h,003h,0EAh,0D0h,002h,0E6h,075h db 020h,0F3h,026h,0CAh,0CAh,0D0h,0DBh,0C6h db 076h,0D0h,0D7h,0F0h,065h,020h,0F4h,026h db 0ADh,0E5h,0FEh,091h,074h,0EAh,0EAh,0EAh db 0C8h,0D0h,0F5h,0E0h,000h,0D0h,00Ch,0C6h db 076h,0F0h,04Fh,020h,0CEh,026h,0A9h,006h db 04Ch,09Fh,025h,0C6h,076h,0A5h,076h,0C9h db 001h,0D0h,0F0h,020h,0CEh,026h,0A9h,000h db 04Ch,09Fh,025h,0B1h,074h,08Dh,0E5h,0FEh db 0EAh,0EAh,0EAh,0C8h,0D0h,0F5h,0E0h,000h db 0D0h,00Ch,0C6h,076h,0F0h,024h,020h,0CEh db 026h,0A9h,007h,04Ch,09Fh,025h,0C6h,076h db 0A5h,076h,0C9h,001h,0D0h,0F0h,020h,0CEh db 026h,0A9h,001h,04Ch,09Fh,025h,0E6h,075h db 0A0h,007h,0B1h,070h,018h,069h,001h,091h db 070h,060h,0A9h,087h,020h,006h,004h,0A5h db 072h,0C5h,0F4h,0F0h,005h,085h,0F4h,08Dh db 030h,0FEh,068h,08Dh,034h,0FEh,0A6h,070h db 0A4h,071h,068h,060h,020h,0F3h,026h,020h db 0F3h,026h,060h oswdfa_end equ offset $ check_winnie: mov al,readstatus mov bx,offset status call sword mov al,byte ptr status+1 and al,020h ret ;entry ds:[si] point to command line ; es points to system data area ;exit seg_address contains segment address ; start_address contains start offset ; end_address contains end offset ; syntax true => syntax error detected ; si points to char after end offset if no syntax error ;comments bx must be preserved in case command line is passed on get_params: mov es:byte ptr syntax,0 ;reset flags mov es:byte ptr pass_on,0 call remsp0 cmp al,cr ;just command only ? jz syntax_error call hexin ;get first address (may be segment) cmp al,cr ;just *command ? jz syntax_error cmp al,':' ;is it seg address ? jnz not_seg_address mov ax,es:in_address ;yes - save it mov es:seg_address,ax call remsp0 cmp al,cr ;just *command ? jz syntax_error call hexin ;get offset cmp al,cr ;just *command ? jz syntax_error not_seg_address: cmp al,' ' ;valid separator ? jnz pass_it_on mov ax,es:in_address ;save start offset mov es:start_address,ax call remove_spaces call hexin ;get end offset cmp al,' ' jnz pass_it_on mov ax,es:in_address ;and save it mov es:end_address,ax ret syntax_error: mov es:byte ptr syntax,-1 ret pass_it_on: mov es:byte ptr pass_on,-1 ret fill: got_fill: call get_params mov al,true ;check for syntax error cmp al,es:byte ptr syntax jz fill_error cmp al,es:byte ptr pass_on jnz keep_it jmp not_fill keep_it: call remove_spaces ;get fill byte cmp al,cr ;if no fill byte whinge jz fill_error call hexin call remove_spaces ;if there's anything else complain cmp al,cr jnz fill_error push es mov cx,es:end_address sub cx,es:start_address ;get length into cx mov di,es:start_address ;start into di mov ax,es:in_address ;fill byte or word into al mov es,es:seg_address ;seg into es cmp ah,0 ;byte or word fill ? jnz word_fill floop: stosb ;n.b. - loop is used not rep so that cx=0 loop floop ;fills 64kbyte block jmps fill_done word_fill: or cx,cx ;32k word fill ? jz max_word_fill cmp cx,1 ;0 word fill ? jz fill_done shr cx,1 ;divide by 2 jmps wloop max_word_fill: mov cx,08000h wloop: stosw loop wloop fill_done: pop es jmp cli_ret fill_error: db 0cdh,04fh,0feh,'Syntax : f (:) ' db ' ',0 search_error: db 0cdh,04fh,0feh,'Syntax : sr (:) (start offset>' db ' <"string">',0 ; Memory search routine ; --------------------- ;comments - n.b. the end address specified is the end address + 1 of the ;search area (for acron consistency) - hence ffff restricts the search area ;to fffe - so to allow searching to be done right up to the end of the segment ;an end address of 0 can be specified i.e. *sr 4000 0 "eric" will search from ;4000 up to ffff inclusive. The condition for a string to be found is that it ;must be wholly contained within the search area i.e. if string "eric" lives ;at 03ffdh then *sr 0 4000 "eric" will not report it but if our string "eric" ;lives at 03ffch then the above search will find him. ;All the usual escape sequences are supported in the string to allow specific- ;ation of control codes etc as follows ;escape sequence hex byte ; "|@" 0 ; "|a" or "|A" 1 ; to to ; "|z" or "|Z" 1A ; "|[" 1B ; to to ; "|_" 1F ; "| " 20 ; to to ; "~" 7E ;except for following two special cases ; """" 22 ; "||" 7C ;delete is entered as follows ; "|?" 7F ; "|!" 80 - FF where is any of above 7 bit ; chars ;note the following will be interpreted as Bad strings ; "abc no terminating " ; "ab"" single quotes ; "ab"""" single quotes ; "a|" no argument to escape char ; "" null string ; "|" reduced to null string - hence as above ; "|!" reduced to null string ;note any escape arguments not recognised are reduced to the argument alone ;i.e. "|1" is reduced to "1" etc ;and any surplus redundant |! operators are ignored ;i.e. "|!|!|@" is reduced to "|!|@" search: mov al,[si] and al,0dfh cmp al,'R' jz got_search jmp not_search got_search: call get_params mov al,true cmp al,es:byte ptr syntax jz search_error cmp al,es:byte ptr pass_on jnz got0 jmp not_search got0: call remove_spaces cmp al,cr jz search_error cmp al,'"' ;have we got a string to look for ? jnz search_error inc si ;might have - save start call process ;on return si = start ; cx = length ;set bx=length of search string ; si=start offset of search string mov bx,cx or bx,bx jnz not_null_string jmp bad_string not_null_string: push es mov cx,es:end_address ;cx=end address mov di,es:start_address ;es:[di] point to search area mov es,es:seg_address cld ;forward direction ;entry ds:si point to search string ; es:di point to search area ; bx length of search string ; cx end offset of search area ;saved bx , cx , si sloop: mov al,escflg ;help ! - i want to escape test al,080h jz keep_searching jmp esc_nl keep_searching: mov ax,di ;check if whole string contained in add ax,bx ;search area jc search_done ;check for overflow or cx,cx jz sloop1 ;trap special case when cx = 0 cmp ax,cx ja really_done ;thank you and goodnite sloop1: push cx push si mov cx,bx ;set up length of search string repz cmpsb jnz no_match call report no_match: pop si pop cx jmps sloop search_done: jnz really_done ;if overflowed and > 0 we've finished or cx,cx ;ok if cx=0 then we might have one jnz really_done ;more match mov cx,bx repz cmpsb jnz really_done call report really_done: pop es jmp cli_ret ;entry di end of string in search area + 1 ; bx length of search string report: push bx push di sub di,bx ;di = start of string in search area mov bx,es call hexword mov al,':' call wrch mov bx,di call hexword call newl ;stuff out new line pop di pop bx ret ;entry si points to first char after opening " ;exit bx points to first char after opening " of processed string ; (same as si on entry if no escape chars in string) process: mov bx,si sub cx,cx ;use cx to count string length p0: mov al,[si] cmp al,'|' ;is it escape char ? jnz not_esc call control_char ;map | to control code jmps next_char not_esc: cmp al,'"' jnz not_quotes ;not special char - so leave alone mov al,1[si] ;its " - check next char cmp al,' ' jz process_done cmp al,cr jz process_done cmp al,'"' jnz bad_string call quotes jmps next_char not_quotes: cmp al,cr ;moan if no closing quotes jz bad_string not_return: cmp top_bit,true jnz next_char add al,080h mov [si],al mov top_bit,false next_char: inc si inc cx jmps p0 process_done: mov si,bx ret bad_string: db 0cdh,04fh,0feh,'Bad string',0 ;entry si points to escape char | ; bx points to start of string i.e. char after first " ;saved bx , cx control_char: inc si mov al,[si] cmp al,'a' jc not_lower_case cmp al,'z'+1 jnc not_lower_case and al,0dfh not_lower_case: cmp al,'@' jc not_0_to_31 cmp al,'_'+1 jnc not_0_to_31 sub al,'@' ;map "@" - "_" to 00h 0 01fh squash_it: cmp top_bit,true jnz leave_top_bit add al,080h ;we had a |! previously leave_top_bit: mov [si],al mov top_bit,false ;reset top_bit flag call squash leave: ret not_0_to_31: cmp al,'?' jnz not_q mov al,07fh ;stuff in delete jmps squash_it not_q: cmp al,'|' jz squash_it ;reduce || to | not_bar: cmp al,'!' jnz squash_it mov top_bit,true ;set top bit flag call squash inc si call squash dec si dec cx ;dec counter as |! doesn't count as a char ret ;reduce "" to " ;entry si points to first " ;exit si points to second " (first removed) quotes: inc si jmps squash_it ;entry si points to char after | ; bx points to start of string ;saved bx , cx squash: push si push bx push cx mov cx,si sub cx,bx dec cx ; number of chars to move jz squashed ;if its zero we've finished add bx,cx dec bx ; bx points to source dec si ; si points to destination sq_loop: mov al,[bx] ; squash string replacing | with mov [si],al ; single byte dec bx dec si loop sq_loop squashed: pop cx pop bx inc bx ;update start of string pop si ret not_search: not_fill: not_xfer: jmp send_line xfer_error: db 0cdh,04fh,0feh,'Syntax : tfer (:)' db ' |',0 xfer: inc si mov al,[si] and al,0dfh cmp al,'F' jnz not_xfer inc si mov al,[si] and al,0dfh cmp al,'E' jnz not_xfer inc si mov al,[si] and al,0dfh cmp al,'R' jnz not_xfer call remsp0 cmp al,cr jz xfer_error call hexin cmp al,' ' jz x0 jmp not_xfer x0: mov di,es:in_address ;di= host address call remsp0 call hexin cmp al,':' jnz not_segment mov ax,es:in_address mov es:seg_address,ax call remsp0 call hexin cmp al,' ' jz not_segment jmp xfer_error not_segment: mov dx,es:in_address ;dx= parasite address call remove_spaces call hexin cmp al,' ' jz x1 jmp xfer_error x1: mov cx,es:in_address ;cx = length call remsp0 and al,0dfh cmp al,'R' jz xfer_read cmp al,'W' jz x2 jmp xfer_error x2: mov al,q_block_write jmps xfer_write xfer_read: mov al,q_block_read xfer_write: push ax call remsp0 cmp al,cr ;rom number given ? jz no_rom_number call shexin jnc good_hex cmp al,'S' jnz knots mov bl,020h ;b5 = 1 => use shadow jmps use_shadow_memory knots: cmp al,'M' jz mmmmm jmp xfer_error mmmmm: mov bl,040h ;b6 = 1 => use screen jmps use_screen_memory good_hex: mov bl,al ;save rom number in bl jmps rom_specified no_rom_number: mov bl,010h ;b4 = 1 => use default rom use_screen_memory: use_shadow_memory: rom_specified: pop ax mov es:byte ptr block+13,bl mov es:byte ptr block+12,al mov es:word ptr block+2,di mov es:word ptr block+6,dx mov ax,es:seg_address mov es:word ptr block+8,ax mov es:word ptr block+10,cx mov ax,es ;set up ds to point to cb mov ds,ax mov bx,offset block mov al,0fah call sword jmp cli_ret ;entry bl rom number to select rom_select: mov al,1 call rw_current_rom call select ret ;entry al 0 => write ; 1 => read rw_current_rom: push es push bx push ax sub ax,ax mov es,ax mov bx,ram_copy mov di,offset current_rom mov cx,1 pop ax call q_read_write pop bx pop es ret select: push es push bx sub ax,ax mov es,ax mov es:rom_number,bl mov bx,ram_copy mov di,offset rom_number mov cx,1 ;note al already 0 call q_read_write pop bx mov al,097h ;*fx 151,48,n mov bh,bl mov bl,030h call sbyte pop es ret rom_restore: sub ax,ax call rw_current_rom mov bl,es:current_rom call select ret ; mon ; --- mon: inc si ;give me an o ? mov al,[si] and al,0dfh cmp al,'O' jnz send_to_oscli inc si ;give me an n ? mov al,[si] and al,0dfh cmp al,'N' jnz send_to_oscli call remsp0 ;and a cr ? cmp al,cr jnz send_to_oscli ;ok i think we've got a *mon command so re_enter monitor and reset various ;bits and pieces jmp monitor ; go ; -- ;entry si points to command line ; ds points to system data area go: inc si ;check next char mov al,[si] and al,0dfh cmp al,'O' ;is it O ? jnz send_to_oscli call remsp0 ;yes might have go command cmp al,cr ;just *go command ? jz use_last_address call hexin ;get address cmp al,cr ;just *go
? jz use_current_ds cmp al,':' ;segment address ? jnz send_to_oscli ;no can't be go command then mov ax,es:in_address ;save segment address mov es:seg_address,ax call remsp0 ;and get offset field cmp al,cr ;just *go : ? jz use_last_address call hexin call remove_spaces cmp al,cr ;valid address ? jnz send_to_oscli use_current_ds: use_last_address: mov ax,es:in_address ;transfer segment:offset to mov es:i_r1r4_off,ax ;i_r1r4 ptr and check code mov ax,es:seg_address mov es:i_r1r4_seg,ax jmp cli_run send_to_oscli: jmp send_line ; dump ; ---- ;entry si point to command line ;nb must preserve bx if not dump command dump: call remsp0 ;skip spaces cmp al,cr ;just *d command ? jz d3 call hexin ;no get first address field (may be seg address) ; call remove_spaces cmp al,cr ;just *d ? jz d2 cmp al,':' ;is it seg address ? jnz d0 mov ax,es:in_address ;yes save segment address mov es:seg_address,ax notseg: call remsp0 cmp al,cr ;just *d : ? jz d3 call hexin ;get next address field into in_address cmp al,cr ;is it cr ? jz d2 d0: cmp al,' ' ;no is it a space ? jnz dos ;no - check for *dos command d1: mov bx,es:in_address ;save start address in bx call remove_spaces call hexin ;get second address into in_address mov si,es:in_address jmps dump1 d2: mov ax,es:in_address ;no end address given - use start + 080h mov es:start_address,ax d3: mov ax,es:start_address ;no start or end address - use end address add ax,080h ;of last dump mov es:end_address,ax dump4: mov bx,es:start_address ;set up start address dump5: mov si,es:end_address ;set up end address dump1: mov al,es:escflg ;escape pressed ? test al,080h jz no_esc jmp esc_nl no_esc: call newl call dump16 call check_dump_end jc dump1 mov es:start_address,bx call newl jmp cli_ret ; dos ; --- dos: mov al,[si] and al,0dfh cmp al,'O' jnz send_to_oscli1 inc si mov al,[si] and al,0dfh cmp al,'S' jnz send_to_oscli1 call remsp0 cmp al,cr jnz send_to_oscli1 jmp boot send_to_oscli1: jmp send_line set_error: db 0cdh,04fh,0feh,'Syntax : s (:) ',0 ; set ; --- set: call remsp0 cmp al,cr ;just *set ? jz set_error call hexin call remove_spaces cmp al,cr ;just *set jz use_set_ds cmp al,':' jz set0 jmp search set0: mov ax,es:in_address ;save segment address mov es:seg_address,ax call remsp0 cmp al,cr ;just *s jz set_error call hexin call remove_spaces cmp al,cr jnz send_to_oscli1 ;ok we've got a *s command don't need to preserve ds anymore ;ds now set up to point to system data in page 5 ;es set up to point to data to be modified use_set_ds: push es sub ax,ax ;ds points to system data mov ds,ax mov ax,ds:seg_address ;use es for modifying data mov es,ax mov al,4 ;*fx4 2 mov bl,2 call sbyte push bx mov al,225 ;*fx 225 128 0 mov bx,128 call sbyte push bx mov al,226 ;*fx 226 133 0 mov bx,133 call sbyte push bx mov dl,11 ;set cursor position display_next_line: mov bx,ds:in_address ;get start address in bx call newl call dump16 ;chuck out 16 bytes mov cl,dl ;move cursor to first hex field call move_cursor reset: call rdch ;read kbd char mov ah,ds:escflg ;better test for escape i suppose test ah,080h jz not_escape pop bx mov bh,0 mov al,226 call sbyte pop bx mov bh,0 mov al,225 call sbyte pop bx mov al,4 ;*fx4 - reset cursor keys call sbyte pop es jmp esc_nl not_escape: cmp al,08bh jc update_memory cmp al,095h jnc update_memory ;trap anything above 94h sub al,08bh ;convert to 0 - 9 mov ah,0 add ax,ax ;double to use as index in table mov bx,offset cursor_table ;get start of table add bx,ax ;bx now points to routine we want mov ax,[bx] ;get address of routine into ax call ax jc display_next_line jmps reset update_memory: call update jc display_next_line jmps reset ;entry al kbd char update: push ax call locate_cursor ;bh=y ; bl=x jnc update_text pop ax call shexin ;return digit in ch jnc valid_hex clc ret valid_hex: mov ch,al ;save in ch sub bl,hex_field_start mov al,bl mov ah,0 mov cl,3 div cl add ax,ds:in_address mov bx,ax mov al,es:[bx] shl al,1 shl al,1 shl al,1 shl al,1 add al,ch jmps up0 update_text: sub bl,text_field_start mov al,bl mov ah,0 add ax,ds:in_address mov bx,ax pop ax up0: mov es:[bx],al ;es points to data segment ;and drop through to display routine display_update: mov ds:display_byte,al call locate_cursor jnc display_in_text push bx ;save cursor position mov al,bs ;move left 1 call wrch mov al,ds:display_byte call hexbyte call move_to_text mov al,ds:display_byte call write_ascii pop bx mov cl,bl mov dl,bl call move_cursor clc ret display_in_text: push bx mov al,ds:display_byte push ax call write_ascii call move_to_hex mov al,bs call wrch pop ax call hexbyte pop bx cmp bl,text_field_end jnz advance_cursor jmp r_new_line advance_cursor: inc bl mov cl,bl mov dl,bl call move_cursor clc ret copy: call locate_cursor jnc c_in_text call move_to_text ret c_in_text: call move_to_hex ret move_to_text: sub bl,hex_field_start mov al,bl mov ah,0 mov cl,3 div cl add al,text_field_start mov cl,al mov dl,al jmp move_cursor move_to_hex: sub bl,text_field_start mov al,bl mov cl,3 mul cl add al,hex_field_start mov cl,al mov dl,al call move_cursor ret left: call locate_cursor ;where the hell's that cursor ? jnc l_in_text cmp bl,hex_field_start jnz left_in_hex sub ds:in_address,16 ;we're at far left so calc address of mov dl,hex_field_end stc ;previous line and set carry ret left_in_hex: mov cx,3 ;move cursor left 3 spaces mov al,bs left1: call wrch loop left1 sub dl,3 ;and update current cursor position ret ;note - carry clear l_in_text: cmp bl,text_field_start jnz left_in_text sub ds:in_address,16 ;we're at far left of text field mov dl,text_field_end stc ;so calc address of previous field ret left_in_text: mov al,bs call wrch sub dl,1 ret right: call locate_cursor jnc r_in_text cmp bl,hex_field_end jnz right_in_hex add ds:in_address,16 mov dl,hex_field_start stc ret right_in_hex: mov cx,3 mov al,ht right1: call wrch loop right1 add dl,3 ret r_in_text: cmp bl,text_field_end jnz right_in_text r_new_line: add ds:in_address,16 mov dl,text_field_start stc ret right_in_text: mov al,ht call wrch add dl,1 ret down: sub ds:in_address,16 stc ret up: add ds:in_address,16 stc ret shift_copy: ret shift_left: call locate_cursor jnc sl_in_text mov cl,hex_field_start mov dl,cl call move_cursor ret sl_in_text: mov cl,text_field_start mov dl,cl call move_cursor ret shift_right: call locate_cursor jnc sr_in_text mov cl,hex_field_end mov dl,cl call move_cursor ret sr_in_text: mov cl,text_field_end mov dl,cl call move_cursor ret shift_down: ret shift_up: ret cursor_table dw offset copy dw offset left dw offset right dw offset down dw offset up dw offset shift_copy dw offset shift_left dw offset shift_right dw offset shift_down dw offset shift_up ;entry cl horizontal cursor position (0 - 79) ;exit none ;used al , bh , cl ;saved bh , cl move_cursor: call read_pos ;read cursor position bh=vpos , bl=pos mov al,31 call wrch mov al,cl call wrch mov al,bh call wrch ret read_pos: mov al,086h jmp sbyte ;entry none ;exit cf set => in hex field ; cf clear => in text field ; bl cursor x position ; bh cursor y position ;used al , bx ;saved none locate_cursor: call read_pos cmp bl,hex_field_end+1 ret ; dump16 ; ------ ;entry bx offset ; seg_address segment ;exit bx = bx + 16 dump16: push es sub ax,ax mov es,ax push bx ;write out segment address mov bx,es:seg_address call hexword mov al,':' call wrch pop bx call hexword ;output bx push ds mov ax,es:seg_address ;set up ds for dump loop mov ds,ax mov cx, 16 ;set count push bx ;save start address for ascii display dump16_loop: mov al, ' ' call wrch mov al,[bx] ;output byte call hexbyte inc bx loop dump16_loop ;do next byte mov cx,16 pop bx ;get start address back for ascii loop mov al,' ' call wrch dump3: mov al,[bx] call write_ascii inc bx loop dump3 pop ds pop es ret ;entry bx contains current dump address ; si contains end address ;exit c => end address not reached ; nc => end address reached ;used bx , si ;saved all check_dump_end: push bx sub bx,8 jnc no_overflow sub bx,bx ;reset bx if overflow jmps overflow no_overflow: pop bx push bx overflow: dec bx sub bx,si ;set carry flag and return pop bx ret ;entry al contains byte to write out ;used ax ;saved ax write_ascii: cmp al,' ' ;< &20 ? jc nonasc cmp al,07fh ;> &7e ? jc asc nonasc: mov al,'.' asc: jmp wrch ;entry bx contains word to output ;used ax , bx ;saved bx hexword: mov al,bh call hexbyte mov al,bl ;entry al contains byte to output ;used ax ;saved none hexbyte: ;------- push ax shr al, 1 shr al, 1 shr al, 1 shr al, 1 call hexnibble pop ax hexnibble: and ax,0fh cmp al, 10 jb hexdigit add al, 7 hexdigit: add al, '0' jmp wrch ;entry al char to convert to hex ;exit ch hex digit ;used al ;saved none shexin: test al,040h jz not0_9 and al,0dfh not0_9: cmp al,'0' jc not_hex cmp al,'F'+1 jnc not_hex cmp al,'9'+1 jc its_0_9 cmp al,'A' jc not_hex add al,9 its_0_9: and al,0fh clc ret not_hex: stc ret ;entry si points to char ;exit in_address contains hex address ; si points to first non hex character ; al contains first non hex character ;used al , bx , si ;saved bx hexin: push bx sub bx,bx hxin1: mov al,[si] test al,040h ;case equate if not 0 to 9 jz hxin2 and al,0dfh hxin2: cmp al,'0' jc hxret ;return if al < &30 cmp al,'F'+1 jnc hxret ;return if al > &46 cmp al,'9'+1 jc hxin3 cmp al,'A' jc hxret add al,9 hxin3: and al,0fh shl bx,1 shl bx,1 shl bx,1 shl bx,1 or al,bl ;put in low digit mov bl,al inc si mov es:in_address,bx jmps hxin1 hxret: pop bx ret ; ;Function prints message ; ;Entry parameters bx points to start of message ;Exit parameters none ; ;Registers used ax,bx,si ;Registers preserved all ; ;Comments pmsg: ;==== mov si, bx ;get start of string cld ;set forward direction pmsg_loop: lodsb ;al <- [si] ; si = si + 1 call wrch ;no write it out test al, al ;last char ? jnz pmsg_loop ret ;pmsg which doesn't send terminating zero smsg: mov si,bx cld smsg_loop: lodsb test al,al jz smsg_end call wrch jmps smsg_loop smsg_end: ret put_r2: ; send register AL across tube using 2nd tube channel ;====== push ax put_r2_loop: in al, r2stat shl al, 1 jns put_r2_loop pop ax out r2data, al ret get_r2: ; read one byte from tube register 2 ;====== in al, r2stat test al, al jns get_r2 in al, r2data ret put_r1: ; send register AL across tube using 1st tube channel ;====== push ax put_r1_loop: in al, r1stat shl al, 1 jns put_r1_loop pop ax out r1data, al ret get_r1: ; get register AL across tube using 1st tube channel ;====== in al, r4stat ; R4 interrupt pending? test al, al ; test if data from R4 js get_r1_prot ; yes, go & start up protocol in al, r1stat ; else check R1 test al, al ; data from R1? jns get_r1 ; loop until data from R1 or R4 avail in al, r1data ; read data from R1 ret ; done get_r1_prot: push ds push es pusha call r4_interrupt_service popa pop es pop ds jmps get_r1 put_r4: ; send register AL across tube using 4th tube channel ;====== push ax put_r4_loop: in al, r4stat ; read tube status test al, al ; R4 interrupt? js put_r4_prot ; yes, go and start protocol shl al, 1 ; else test for space in R4 jns put_r4_loop ; wait for int or space pop ax ; space in tube out r4data, al ; stick data into tube ret put_r4_prot: ; start up R4 protocol push ds push es pusha call r4_interrupt_service popa pop es pop ds jmps put_r4_loop ; read one byte from tube register DX using ; status register DX-2 read_tube: ;--------- push dx mov dh, 0 dec dl dec dl rt_wait: in al, dx test al, al jns rt_wait inc dl inc dl in al, dx pop dx ret ; write one byte to tube register DX using ; status register DX-2 write_tube: push dx push ax mov dh, 0 dec dl dec dl wt_wait: in al, dx shl al, 1 jns wt_wait inc dl inc dl pop ax out dx, al pop dx ret write_r2: ; write AH to register 2 ;-------- pushf push ax waitR2wr: in al, r2stat test al, 40h jz waitR2wr mov al, ah out r2data, al pop ax popf ret read_r2: ;------- pushf xchg ah, al waitR2rd: in al, r2stat test al, 80h jz waitR2rd in al, r2data xchg ah, al popf ret readr1: ;------ pushf xchg al, ah waitR1rd: in al, r1stat test al, 80h jz waitR1rd in al, r1data xchg al, ah popf ret readr4: ;------ pushf xchg al, ah waitR4rd: in al, r4stat test al, 80h jz waitR4rd in al, r4data xchg al, ah popf ret string: ; send the string pointed to by BX, terminate after CR ;------ push bx string1: mov al, [bx] call put_r2 cmp byte ptr [bx], cr ; was last ch a CR je string_exit inc bx jmps string1 string_exit: pop bx ret osrdch_int: sti call rdch ;ok this is a bit sordid but the int has gone and put the flags on the stack ;and the iret is going to stomp all over any flags that the os routine sets ;unless we do something about it os_flag_return: push bp push ax ;stack now looks like this ; sp+8 | flags | ; sp+6 | cs | ; sp+4 | ip | ; sp+2 | bp | ; sp -> | ax | mov bp,sp ;set up bp to access stack lahf ;get flags into ah (sf,zf,af,pf,cf) mov byte ptr 8[bp],0 or byte ptr 8[bp],ah ;set flags on stack pop ax pop bp iret ; osrdch ; ------ ;Function Read a character from currently selected input stream ; ;Entry Parameters NONE ;Exit Parameters al character ; CF Clear => Successful read ; CF Set => Error , error type in al i.e. if ; al = 01BH then escape condition detected and all subseq- ; uent calls will return 01BH until escape is acknow- ; ledged ;Register use ax ;Preserved registers rdch: xchg al, ah mov ah, rdchno call write_r2 rdcha: call read_r2 not ah cmp ah, 128 ; set the carry flag if required call read_r2 xchg al, ah ret osasci_int: sti cmp al,cr jnz oswrch_int osnewl_int: sti mov al,lf call wrch mov al,cr oswrch_int: sti call wrch jmp os_flag_return asci: cmp al,cr jnz wrch newl: mov al,lf call wrch mov al,cr ; oswrch ; ------ ;Function Write character to currently selected o/p stream ;Entry parameters al character ;Exit parameters none ;Register use ax ;Preserved registers al wrch: xchg al, ah oswrch_loop: in al, r1stat shl al, 1 jns oswrch_loop xchg al, ah out r1data, al ret oswrch_string: ; write string @ si, length cx characters ;------------- mov dx, r1data oswrch_string_loop: in al, r1stat shl al, 1 jns oswrch_string_loop outsb al loop oswrch_string_loop ret oscli_int: sti call cli jmp os_flag_return ; oscli ; ----- ;Function sends command to cli ; ;Entry parameters bx points to command line ;Exit parameters none ; ;Registers used ax , bx , cx , dx , si ;Registers preserved all ; ;Comments cli: push ax push bx push cx push dx push si push ds push es sub ax,ax ;set up ds for *go , *d etc mov es,ax mov si,bx ;use si to point to command line cli1: call remove_stars ;remove leading *'s call remove_spaces ;remove leading spaces cmp al,'*' ;any more leading *'s ? jz cli1 and al,0dfh cmp al,'H' jz help cmp al,'D' jnz not_d jmp dump not_d: cmp al,'F' jnz not_f jmp fill not_f: cmp al,'G' jnz not_go jmp go not_go: cmp al,'M' jnz not_m jmp mon not_m: cmp al,'S' jnz not_s jmp set not_s: cmp al,'T' jnz not_t jmp xfer not_t: jmp send_line help: inc si mov al,[si] cmp al,'.' jz grab_help_command and al,0dfh cmp al,'E' jnz send_line inc si mov al,[si] cmp al,'.' jz grab_help_command and al,0dfh cmp al,'L' jnz send_line inc si mov al,[si] cmp al,'.' jz grab_help_command and al,0dfh cmp al,'P' jnz send_line inc si mov al,[si] call check_text jnc send_line grab0: call remove_spaces jmps grab1 grab_help_command: call remsp0 grab1: cmp al,cr ;have we got a command tail ? jnz check_tail ;yes check tail for monitor commands call write_help_message ;and pass on command call write_subheading send_line: mov al, clino call put_r2 call string call get_r2 cmp al,080h ;*run command ? jz cli_run cli_ret: pop es pop ds pop si pop dx pop cx pop bx pop ax ret cli_run: mov es:cli_flag,1 ;set *run flag note ds must be 0 here push es:exec_off ;save exec address push es:exec_seg call runit mov ax,0 ;reset ds in case code's stomped on it mov es,ax pop es:exec_seg pop es:exec_off jmps cli_ret check0: inc si mov al,[si] check_tail: cmp al,'.' jz got_mon and al,0dfh cmp al,'M' jz grbhp2 cmp al,cr jz send_line grlop1: inc si mov al,[si] cmp al,cr jz send_line cmp al,' ' jnz grlop1 jmps check0 grbhp2: inc si mov al,[si] cmp al,'.' jz got_mon and al,0dfh cmp al,'O' jnz grlop1 inc si mov al,[si] cmp al,'.' jz got_mon and al,0dfh cmp al,'N' jnz grlop1 inc si mov al,[si] call check_text jnc grlop1 got_mon: call write_help_message call write_info jmp send_line remsp0: inc si remove_spaces: mov al,[si] cmp al,' ' jz remsp0 ret remst0: inc si remove_stars: mov al,[si] cmp al,'*' jz remst0 ret write_help_message: push bx push ds mov ax,es:word ptr .0102h mov ds,ax mov bx,offset help_message call pmsg push sp pop ax cmp ax,sp jz help_286 mov ax,186 jmps help_186 help_286: mov ax,286 help_186: call pdec mov bx,offset help_message1 call pmsg pop ds pop bx ret help_message db cr,lf,'80',0 help_message1 db ' TUBE ',verh,'.',verm,verl,cr,lf,0,'d' write_subheading: push bx push ds mov ax,es:word ptr .0102h mov ds,ax mov bx,offset sub_message call pmsg pop ds pop bx ret sub_message db ' MON',cr,lf,0 write_info: push bx push ds mov ax,es:word ptr .0102h mov ds,ax mov bx,offset info_message call pmsg pop ds pop bx ret info_message db ' d (:) ()' db ' ()',cr,lf db ' dos',cr,lf db ' f (:) ' db ' ',cr,lf db ' go (:) ',cr,lf db ' mon',cr,lf db ' s (:) ',cr,lf db ' sr (:) ' db ' <"string">',cr,lf db ' tfer (:) ' db ' |',cr,lf,0 ; check text ; ---------- ; ;Function check command line tail for alpha character ; i.e. is 'A' < = char < = 'Z' or 'a' < = char < = 'z' ; ;Entry parameters al character to be tested ;Exit parameters c => non alpha char ; nc => alpha char ; ;Registers used al ;Registers preserved none check_text: and al,0dfh cmp al,'A' jc check_done cmp al,'Z'+1 cmc check_done: ret ;entry es must be 0 runit: mov ax,es:i_r1r4_off ;save exec address of code mov es:exec_off,ax mov ax,es:i_r1r4_seg mov es:exec_seg,ax mov es:fault_seg,ax push es lds si,es:dword ptr i_r1r4_off mov bx,ds ;save rom code segment mov cx,si ;and offset add si,7 ;point to copyright offset byte mov dx,si ;dx=si+7 mov al,[si] ;get copyright offset byte into ax mov ah,0 mov si,cx ;get start offset back add si,ax ;ds:[si] now points to copyright string mov es:fault_off,si ;set up fault pointer les di,es:dword ptr copy_ptr ;es:[di] point to 0,'(C)' mov cx,4 ;set up count repz cmpsb pop es jnz run_that_code ;not a sways rom image - assume we can ;run it mov si,dx dec si mov al,es:cli_flag ;*run command ? or al,al jnz star_run mov al,[si] ;get rom type byte test al,040h ;is it a language ? jnz its_a_language jmp boot ;not a langauage - boot cp/m its_a_language: and al,0fh ;mask bits we don't want cmp al,code_186 ;is it 186 code ? jz go4it jmp boot ;no - so boot cp/m instead run_that_code: mov al,es:cli_flag or al,al jnz go4it ;its not *run command - if its a cntrl break then boot dos mov al,es:reset_type or al,al jz go4it jmp boot go4it: jmpf es:dword ptr i_r1r4_off star_run: mov es:cli_flag,0 mov al,[si] test al,040h jz not_a_language and al,0fh cmp al,code_186 jnz not_286_code mov al,1 ;enter language with al=1 jmps go4it not_a_language: db 0cdh,04fh,0ffh,'Not a language',0 not_286_code: db 0cdh,04fh,0ffh,'Not 80186 code',0 copyright db 0,'(C)' osfind_int: sti call find jmp os_flag_return ; osfind ; ------ ;Function Open a file for reading an writing ; ;Entry Parameters al Operation type ; bx Point to filename terminated by cr (A <> 0) ; bh File handle (A = 0) ;Exit Parameters al File handle ; ; ;Register use ax , bx ;Preserved registers bx ;Wait until R2DATA not full , write FINDNO (&12) to R2DATA ;Wait until R2DATA not full , write type of open to R2DATA ;IF type=0 ;THEN [ ; Wait until R2DATA not full , write file handle to R2DATA ; Wait for data in R2DATA , read result ; ] ;ELSE [ ; Wait until R2DATA not full , write file name string to R2DATA ; (including terminating cr) ; Wait for data in R2DATA , read handle from R2DATA ; ] find: push ax ; save the open mode mov al, findno call put_r2 pop ax call put_r2 test al, al jne findln mov al, bh call put_r2 jmps osfind_result findln: call string osfind_result: call get_r2 ret osgbpb_int: sti call gbpb jmp os_flag_return ; osgbpb ; ------ ;Function Read/write block of bytes from/to specified open file ; ;Entry parameters bx Point to control block ; al Contains type of operation ;Exit parameters al = 0 => operation attempted ; al unchanged => Filing system does not support ; this facility ; CF clear => xfer completed OK ; CF set => EOF reached before completion of xfer ;Register use ax , bx , cx , si ;Preserved registers bx , cx , si ;Wait until R2DATA not full , write GBPBNO (&16) to R2DATA ;Wait until R2DATA not full , write 13 byte OSGBPB CB to R2DATA (last byte of ;block is written first) ;Wait until R2DATA not full , write type of transfer to R2DATA ;Waiting for data in R2DATA , read back 13 byte control block from R2DATA ;(last byte of block is read first) ;Wait for data in R2DATA , read R2DATA bit 7 which is 6502_C bit ;Waiting for data in R2DATA , read 6502_A from R2DATA gbpb: push si push cx mov ah, gbpbno call write_r2 mov si, 12 mov cx, 13 gbpb1: mov ah, [bx+si] call write_r2 dec si loop gbpb1 mov ah, al call write_r2 mov si, 12 mov cx, 13 gbpb2: call read_r2 mov [bx+si], ah dec si loop gbpb2 call read_r2 ; set carry flag and get 6502_A in AL ; top bit of AH is the carry flag not ah cmp ah, 128 ; set the carry flag pushf call read_r2 mov al, ah popf pop cx pop si ret osbyte_int: sti call sbyte jmp os_flag_return ; osbyte routine ; -------------- ;Function Access OS functions using parameters passed in HL ; ;Entry Parameters al OSBYTE number ; bx OSBYTE parameters ;Exit Parameters bx contains parameters dependent on call ; CF call dependent ;Register use ax , bx ;Preserved registers al ;IF osbyte number < &80 ;THEN [ ; Wait until R2DATA not full , write SBYTENO (&04) to R2DATA ; Wait until R2DATA not full , write parameter for 6502_X to R2DATA ; Wait until R2DATA not full , write OSBYTE number to R2DATA ; Wait for data in R2DATA , read R2DATA which is 6502_X register ; ] ;ELSE IF OSBYTENO=&82 THEN [result is machine high order address] ;ELSE IF OSBYTENO=&83 THEN [result is low memory value] ;ELSE IF OSBYTENO=&84 THEN [result is high memory value] ;ELSE [ ; Wait until R2DATA not full , write BYTENO (&06) to R2DATA ; Wait until R2DATA not full , write parameter for 6502_X to R2DATA ; Wait until R2DATA not full , write parameter for 6502_Y to R2DATA ; Wait until R2DATA not full , write OSBYTE number to R2DATA ; IF OSBYTENO=&9D THEN RETURN from protocol (no reply) ; Wait for data in R2DATA , bit 7 of byte read is from 6502_C ; Wait for data in R2DATA , byte read is 6502_Y ; Wait for data in R2DATA , byte read is 6502_X ; ] sbyte: cmp al, 128 jae bytsiz sbyte1: ; osbyte with one parameter mov ah, sbytno call write_r2 mov ah, bl call write_r2 mov ah, al call write_r2 call read_r2 mov bl, ah ret bytsiz: ; osbyte's with two params cmp al, 82h ; look out for the exceptions je macadd cmp al, 83h je lomem cmp al, 84h je himem bytea: mov ah, byteno call write_r2 mov ah, bl call write_r2 mov ah, bh call write_r2 mov ah, al call write_r2 cmp al, 9dh je no_reply call read_r2 not ah ; top bit of AH is the carry flag cmp ah, 128 ; set the carry flag pushf call read_r2 mov bh, ah call read_r2 mov bl, ah popf no_reply: ret lomem: himem: macadd: mov bx, 0 ret osword_int: sti call sword jmp os_flag_return ; osword ; ------ ;Function Access OS using control block to pass parameters ;Entry parameters al OSWORD number ; bx Address of control block (CB) ;Returned values CB Number of returned params in CB call dependent ;Register use ax , bx , cx , dx , si ;Preserved registers all ;IF OSWORD number = &00 ;THEN [ ; do readline ; Wait until R2DATA not full , write RDLNNO (&0A) to R2DATA ; Wait until R2DATA not full , write upper bound char to R2DATA ; Wait until R2DATA not full , write lower bound char to R2DATA ; Wait until R2DATA not full , write length allowed to R2DATA ; Wait until R2DATA not full , write &07 to R2DATA ; Wait until R2DATA not full , write &00 to R2DATA ; Wait for data in register 2 => response ; IF response >&7F ; THEN [ ; ;escape was pressed on input ; RETURN from protocol ; ] ; Read a terminated string from R2DATA ; ] ;ELSE [ ; Wait until R2DATA not full , write WORDNO (&08) to R2DATA ; Wait until R2DATA not full , write OSWORD number to R2DATA ; Wait until R2DATA not full , write number of params to send to R2DATA ; Write parameter block to R2DATA , last byte first ; Wait until R2DATA not full,write number of params to receive to R2DATA ; Read bytes back from R2DATA into parameter block , last byte first ;The number of parameters to send/receive is determined by ; 1 <= A <= &14 NTS & NTR found from table ; &15 <= A <= &7F NTS = 16 , NTR = 16 ; A > &7F NTS = (CB + 0) , NTR = (CB + 1) sword: ; AL = OSWORD#, BX is Y,X for 6502 push ax push bx push cx push dx push si mov ah, al mov si, bx call my_osword pop si pop dx pop cx pop bx pop ax ret my_osword: mov dl, r2data test ah, ah jnz osword_cmd mov al,10 ;send rdlnno call write_tube mov cx,3 ;number of params to send mov bx,5 send_readline_parms: ;send [si+4] to [si+2] dec bx mov al,[si+bx] call write_tube loop send_readline_parms mov al,7 ;send first magic number call write_tube mov al,0 ;send second magic number call write_tube call get_r2 ;read response shl al,1 ;response > &7f ? jc readline_end mov bx,word ptr [si] ;get address for command line from cb mov cx,-1 ;initialise count for line length read_loop: ;read chars and stick in buffer call get_r2 mov byte ptr [bx],al inc bx inc cx ;increment counter cmp al,cr ;end of input yet ? jnz read_loop mov bl,0 mov bh,cl clc ret readline_end: mov bx,0ffh ;escape occurred set bh=0 bl=0ffh stc ret osword_cmd: mov al, 8 ; OSWORD code call write_tube mov al, ah call write_tube sub bx, bx cmp ah, 81h jc not_user_osword mov al, 0[si] mov dh, 1[si] jmps send_input_params not_user_osword: cmp ah, 21 jae get_no_of_inputs mov bl, ah get_no_of_inputs: mov al, osword_in_tbl[bx] mov dh, osword_out_tbl[bx] send_input_params: call write_tube mov bl, al test bx, bx jz finish_send mov cx, bx send_input: dec bx mov al, [si+bx] call write_tube loop send_input finish_send: mov al, dh call write_tube sub bh, bh mov bl, dh test bx, bx jz finish_receive mov cx, bx receive_output: dec bx call read_tube mov byte ptr [si+bx], al loop receive_output finish_receive: ret osbput_int: sti call bput jmp os_flag_return ; osbput ; ------ ;Function Write one byte to specified open file ; ;Entry Parameters al Byte to write to file ; bh File handle ;Exit Parameters NONE ; ;Register use ax , bx ;Preserved registers all ;Wait until R2DATA not full , write BPUTNO (&10) to R2DATA ;Wait until R2DATA not full , write file handle to R2DATA ;Wait until R2DATA not full , write byte to put to R2DATA ;Wait for data from R2DATA , discard it (Synchronisation byte) bput: push ax mov al,bputno ;write bputno call put_r2 mov al,bh ;write file handle call put_r2 pop ax ;recover byte to write call put_r2 ;and stuff it down r2data push ax call get_r2 pop ax ret osbget_int: sti call bget jmp os_flag_return ; osbget ; ------ ;Function Read one byte from specified open file ; ;Entry Parameters bh File handle ;Exit Parameters al Byte read from file ; c set if attempt made to read past end of file ;Register use ax , bx ;Preserved registers bx ;Wait until R2DATA not full , write BGETNO (&0E) to R2DATA ;Wait until R2DATA not full , write file handle to R2DATA ;Wait for data in R2DATA , top bit of byte is 6502_C (Validity bit) ;Wait for data in R2DATA , read R2DATA which is byte read from file bget: mov al,bgetno ;write bgetno to r2data call put_r2 mov al,bh ;write file handle to r2data call put_r2 jmp rdcha osargs_int: sti call args jmp os_flag_return ; osargs ; ------ ;Function Read / write file attributes ; ;Entry Parameters al Operation type ; ah File handle ; bx Point to 4 byte attribute block ;Exit Parameters al FS type ; (bx) File attributes ;Register use ax , bx , cx , si ;Preserved registers bx , cx , si ;Comments This is the only call that does not conform to the ; convention of using al,bx instead of A,Y,X because ; the 4 byte attribute block cannot be in zero page ; therefore another register ( ch ) is needed to pass the ; file handle ;Wait until R2DATA not full , write ARGSNO (&0C) to R2DATA ;Wait until R2DATA not full , write file handle to R2DATA ;Waiting for R2DATA not full, ; [write 4 bytes osarg_data to R2DATA (MSB first)] ;Wait until R2DATA not full , write operation code to R2DATA ;Wait for data in R2DATA , read fs type from R2DATA ;Waiting for R2DATA data, ; [read 4 bytes osarg_data from R2DATA (MSB first)] args: push bx push cx push dx push si mov dl,al ;save op type mov al,argsno ;write argsno call put_r2 mov al,ah ;write file handle call put_r2 mov si,3 mov cx,4 osargs1: ;write out (bx+3) to (bx+0) mov al,[bx+si] call put_r2 dec si loop osargs1 mov al,dl ;get op type into al call put_r2 call get_r2 ;read fs type into al mov ah,al ;and save in ah mov si,3 mov cx,4 osargs2: ;read file attributes into (bx+3) to (bx+0) call get_r2 mov [bx+si],al dec si loop osargs2 mov al,ah ;return with fs type in al pop si pop dx pop cx pop bx ret osfile_int: sti call file jmp os_flag_return ; osfile ; ------ ;Function Load/save data , examine/alter catalogue information ; ;Entry Parameters al Operation type ; bx Point to control block ; ;Exit Parameters Operation dependent ; ;Register use ax , bx , cx , si ;Preserved registers all ;Wait until R2DATA not full , write FILENO (&14) to R2DATA ;Waiting for R2DATA not full , write last 16 bytes of OSFILE CB to R2DATA ;(last byte of block is written first) ;Waiting for R2DATA not full , write filename to R2DATA including cr ;Wait until R2DATA not full , write type of transfer to R2DATA ;(Any transfer is completed under interrupt using R3 , R4) ;Wait for data in R2DATA , read R2DATA AND &7F = Filing system type ;Waiting for data in R2DATA , read back 16 byte control block from R2DATA ;(last byte of block is read first) file: push cx push si mov ah,al ;save op type mov al,fileno call put_r2 mov si,17 mov cx,16 osfile1: ;write out (bx+17) to (bx+2) mov al,[bx+si] call put_r2 dec si loop osfile1 ;exit with si=1 dec si mov bx,[si] ;get address of string into bx call string ;send string to r2data (nb preserves bx) mov al,ah ;get op type back call put_r2 call get_r2 ;read object type and al,07fh ;is this ok ? if adfs protected file ;type is &ff mov ah,al ;save in ah mov si,17 mov cx,16 osfile2: call get_r2 mov [bx+si],al dec si loop osfile2 mov al,ah ;return object type in al pop si pop cx ret ; interrupt handler ; ----------------- ; R1 interrupts for events and escape flag update ; ; Byte < 0 => escape flag update , b6 contains new ; logical state of escape flag ; ; Byte >= 0 => event number - event parameters Y,X,A ; are then sent in that order ; ; R4 interrupts for R3 transfers and errors ; ; Byte < 0 => host has detected an error , error ; number and error string follow thro' R2 ; ; Byte >= 0 => initialise R3 transfer ; delay delay/byte ; 0 => Single byte transfer p to h 24 us 24 us ; 1 => Single byte transfer h to p 0 us 24 us ; 2 => Double byte transfer p to h 26 us 26 us ; 3 => Double byte transfer h to p 0 us 26 us ; 4 => No transfer (pass address only) ; 5 => No transfer (filing system release) ; 6 => 256 byte Winnie transfer p to h 19 us 10 us ; 7 => 256 byte Winnie transfer h to p 0 us 10 us ;note first delay is time from removal of synch byte to first byte being ;available in p to h register - in nmi/dma modes (0 and 2) this is the same as ;the delay per byte since nmi's can be accepted as soon as synch byte is ;removed - in polled modes it is the time to provide the first byte from ;the polling loop. ;If actual delay exceeds above spec (or host code doesn't wait long enough) ;then the first byte will be missed and screw up the transfer ;The initial delay is only needed for p to h transfers as in h to p direction ;the transfer is initiated by the host which will transfer the byte when it is ;ready ;Note for type 7 this is not strictly true as parasite is not immediately ;ready to receive a byte after removing the synch byte as it has to test the ;data available bit in r3stat (min 31 cycles = 3.1 us on 10MHz 80186) - but if ;parasite takes longer than 15.5 us to read the first byte it will have been ;overwritten by the second byte and hence lost - this is assuming host code ;for type 7 is as follows ;JSR &406 ;tube initialisation ;LDY #&0 ;1 us ;.loop ;LDA (host),Y ;2.5 us ;STA TPORT ;2 us ;NOP ;NOP ;NOP ;INY ;BNE loop ;i.e. first byte is sent after 5.5 us second after 15.5 us etc ;The transfers are used mainly by filing systems to read and write blocks of ;data across the tube as follows ; filing system transfer used ; dfs 0/1 ; adfs 6/7 and 0/1 ; nfs 2/3 and 0/1 ;i.e. adfs uses the fast 256 byte protocol to transfer the bulk of the file ;and the 1 byte protocols to transfer the rest of it if it is not a multiple ;of 256 bytes in length. ;OSWORD &FA can be set up to use any transfer 0 - 3 or 6 - 7 - monitor command ;*tfer uses 6/7 and 0/1 in similar way to adfs ;Concurrent DOS and DOS PLUS uses types 0 and 1 for the floppy drivers ;and uses adfs in the winnie drivers (hence using 6/7 and 0/1). Screen ;updating for Conc DOS consoles does not use R3/R4 transfers but instead ;uses R1/R2 to achieve a transfer rate of approx 120 Kbytes/s ;anyway enough of this jolly banter - here's the code i_r1r4: ; register 1/register 4 event -- tube hardware interrupt ;====== pusha push ds push es mov dx, int_eoi ;remove int (nb should only on 186) mov ax, eoi_nspec out dx, ax mov ax,0 ;set up ds , es to access system data mov ds,ax mov es,ax in al, r4stat ;r4 interrupt ? test al, 80h jz not_r4_int call r4_interrupt_service ;yes - service it jmps r1r4_done not_r4_int: in al, r1stat ;r1 interrupt ? test al, 80h jz r1r4_done mov dx, r1data ;yes in al, dx test al, 80h ;event or escape flag update jns not_esc_updt shl al,1 ;bit 6 is escape flag mov ds:escflg,al jmps r1r4_done not_esc_updt: call get_r1 mov bh, al call get_r1 mov bl, al call get_r1 not_r1_int: r1r4_done: pop es pop ds popa iret r4_interrupt_service: ;-------------------- mov dx, r4data ;read r4data in al, dx shl al, 1 ;error or block transfer ? jnc r4_protocol r4_error: ;-------- mov dx, r2data ;flush r2 call read_tube mov di,offset error_buffer ;point to error buffer mov al,0cdh stosb mov al,04fh stosb call read_tube stosb r4_error_loop: call read_tube test al, al jz r4_error_done stosb r4_error_ign: jmps r4_error_loop r4_error_done: stosb ;put terminating 0 in buffer sti jmpf cs:dword ptr error_jump error_jump dw offset error_buffer dw 0 ;ok we've had an error either from 6502 or 186 - set up the fault pointer ;and jump to error handler at 0000:05f8 ;note brk can be entered directly after 186 error or within i_r1r4 routine ;if 6502 error - hence ds must be set up again in case its a 186 error brk: sti sub ax,ax mov ds,ax ;set up ds to access data pop ax mov ds:fault_off,ax ;save offset of error string pop ax mov ds:fault_seg,ax ;save segment of error string jmpf ds:dword ptr brk_off ;the default system error handler - writes out error , restores ds and ;returns to monitor cli loop default_brk: lds si,ds:dword ptr fault_off call newl inc si ;skip error number cld error_loop: lodsb call wrch test al,al ;end of string ? jnz error_loop call newl jmp monitor r4_protocol: ;----------- ;dma channel must be disabled before the 4 byte transfer address is removed ;because tube may generate spurious drq's in some circumstances (see above ;for more info) push ax push dx mov ax,dma_disable ;disable dma channel mov dx,dma0_control out dx,ax pop dx pop ax shr al, 1 ; restore original type code mov ds:i_r1r4_type, al ; save function code call read_tube ; read from R4 cmp ds:i_r1r4_type, 5 ; end of transfer? jne i_r1r4_blkxfr ; no, block transfer ;this is where the dma channel used to be disabled ; mov ax,dma_disable ;disable dma channel ; mov dx,dma0_control ; out dx,ax mov ds:i_r1r4_dma_busy, false ; that's it... ret ; return from R4_PROTOCOL i_r1r4_blkxfr: mov cx, 4 ; fetch four byte Xfer address mov di, offset i_r1r4_off+3 ; point to double word std ; get MSB first (took me 1 hour...) i_r1r4_dma_loop: call read_tube ; get byte from R4 stosb ; save in double word loop i_r1r4_dma_loop ; four bytes in total cld cmp ds:i_r1r4_type, 4 ; address xfer only? je i_r1r4_sync ; just fetch sync, done cmp ds:i_r1r4_type, 6 ; non-interrupt driven xfer? jae i_r1r4_type67 ; yes, read or write? ;ok its a type 0 - 3 transfer so use nmi routine on 286 or dma routine on ;186 push sp pop ax cmp ax,sp jz nmi_286 jmp type0_3 nmi_286: mov bx, i_r1r4_off ; get offset of dma address mov nmi0_off, bx ; and fiddle nmi code ... mov nmi1_off, bx ; for nmi0 and nmi1 mov bx, i_r1r4_seg mov nmi0_seg, bx mov nmi1_seg, bx mov bl, ds:i_r1r4_type mov bh, 0 shl bx, 1 mov ax, nmi_table[bx] sub bx, bx push es mov es, bx mov di, 8 ; offset of NMI in int vector table stosw mov ax, cs stosw pop es i_r1r4_sync: in al, r4stat test al, 80h jz i_r1r4_sync in al, r4data ret i_r1r4_type67: cmp ds:i_r1r4_type,6 jne i_r1r4_type7 i_r1r4_type6: push ds lds si, ds:dword ptr i_r1r4_off mov cx, 257 ; Bug in 6502 code... mov dx, r3data ; wait for data type6_sync: in al, r4stat test al, al jns type6_sync in al, r4data type6_wait: in al, r3stat shl al, 1 jns type6_wait outsb al loop type6_wait pop ds ret i_r1r4_type7: push es les di, ds:dword ptr i_r1r4_off mov cx, 256 mov dx, r3data type7_sync: in al, r4stat test al, al jns type7_sync in al, r4data type7_loop: in al, r3stat and al, al jns type7_loop insb loop type7_loop pop es ret type0_3: test ds:i_r1r4_type,1 jnz htop ;parasite to host transfer ptoh: call write_dma jmp i_r1r4_sync ;host to parasite transfer htop: call read_dma jmp i_r1r4_sync write_dma: mov ax,ds:i_r1r4_seg ;segment value into ax rol ax,1 ;move bits 19-16 of physical address to low rol ax,1 ;4 bits of register rol ax,1 rol ax,1 mov bx,ax ;save in bx mov dx,dma0_source_upper ;set up upper 4 bits of dma source out dx,ax and ax,0fff0h ;mask out top 4 bits of physical address add ax,ds:i_r1r4_off ;add offset (may set carry) mov dx,dma0_source_lower ;set up lower 16 bits of dma source out dx,ax jnc ptoh_nocarry inc bx ;carry set - better add to top 4 bits mov ax,bx mov dx,dma0_source_upper ;bash top 4 bits again out dx,ax ptoh_nocarry: mov ax,r3data ;set up lower 16 bits of dma dest mov dx,dma0_dest_lower out dx,ax xor ax,ax ;and reset top 4 bits cos tubes in io space mov dx,dma0_dest_upper out dx,ax mov ax,dma_write ;light blue touch paper mov dx,dma0_control ;and stand well clear ... out dx,ax ret read_dma: mov ax,ds:i_r1r4_seg rol ax,1 rol ax,1 rol ax,1 rol ax,1 mov dx,dma0_dest_upper out dx,ax mov bx,ax and ax,0fff0h add ax,ds:i_r1r4_off mov dx,dma0_dest_lower out dx,ax jnc htop_no_carry inc bx mov ax,bx mov dx,dma0_dest_upper out dx,ax htop_no_carry: mov ax,r3data mov dx,dma0_source_lower out dx,ax xor ax,ax mov dx,dma0_source_upper out dx,ax mov ax,dma_read mov dx,dma0_control out dx,ax ret ; now lets have some 'orrible self modifying nmi code - and lets hope ; it's fast enough nmi0: push ds push ax plant0 rw 0 nmi0_seg equ plant0 + 1 mov ax, 0 mov ds, ax ; 1 clock faster than DS direct plant1 rw 0 nmi0_off equ plant1 + 1 mov al, byte ptr .0 out r3data, al inc nmi0_off pop ax pop ds iret nmi1: push ds push ax plant2 rw 0 nmi1_seg equ plant2 + 1 mov ax, 0 mov ds, ax ; 1 clock faster than DS direct in al, r3data plant3 rw 0 nmi1_off equ plant3 + 1 mov byte ptr .0, al inc nmi1_off pop ax pop ds iret nmi2: push ds push si push dx mov dx, r3data cld lds si, cs: dword ptr i_r1r4_off outsb al outsb al mov cs: i_r1r4_off, si pop dx pop si pop ds iret nmi3: push es push di push dx mov dx, r3data cld les di, cs: dword ptr i_r1r4_off insb insb mov cs: i_r1r4_off, di pop dx pop di pop es iret osword_in_tbl db 16 db 0, 5, 0, 5, 2 db 5, 8, 14, 4, 1 db 1, 5, 0, 1, 32 db 16, 13, 0, 8, 128 osword_out_tbl db 16 db 5, 0, 5, 0, 5 db 0, 0, 0, 5, 9 db 5, 0, 8, 25, 0 db 1, 13, 128, 8, 128 i_r1r4_stack dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch dw 0cccch, 0cccch, 0cccch, 0cccch i_r1r4_tos rw 0 i_r1r4_ss dw 0cccch i_r1r4_sp dw 0cccch nmi_table dw offset nmi0 dw offset nmi1 dw offset nmi2 dw offset nmi3 ;ram test entry point for first 64k ;this is only executed when the m/c is first switched on cos it takes quite ;a long time and stomps over the non copied ram in page 5 ram_test: sub ax,ax mov ds,ax mov es,ax ;ds=es=0 mov bx,offset first mov cx,4 t_checksum: add al,byte ptr [bx] adc ah,0 inc bx loop t_checksum cmp ax,neilck jnz do_the_test mov ds:byte ptr first_flag,0 jmp copy_rom ;entry ds,es point to segment to test do_the_test: mov ax,0aaaah ;set up test pattern test_next_bit: mov cx,08000h ;do 64k i.e. 32k words mov bx,cx ;save count cld ;forward direction mov dx,ax ;save test pattern sub di,di ;di=0 rep stosw ;es:[di] <- ax ; di = di + 2 ;on exit from rep di=cx=0 mov cx,bx ;recover count sub si,si test_next_word: lodsw ;ax <- ds:[si] ; si = si + 2 xor ax,dx ;test pattern as written ? jnz rw_fault ;type 0 error at si-2 wordok: loop test_next_word mov ax,dx ;recover ax cmp ax,05555h jz do_next_test mov ax,05555h jmps test_next_bit ;registers now set up as follows ;di = 0 , bx = 08000h , es = ds = 0 do_next_test: sub ax,ax mov cx,bx ;clear memory for next test rep stosw mov dl,1 ;set up error type sub si,si ;use si for address test_address_lines_joined: mov di,si ;save si mov ax,-1 ;set up test pattern mov [si],al ;write test byte to first byte of block or si,si jnz next_test inc si ;si=1 jmps test_address_low_or_high next_test: mov dl,3 ;set up error type shl si,1 test_address_low_or_high: mov al,[si] cmp al,0 jnz address_fault ;type 1 error at 0/si or type 2 at di/si shl si,1 jnz test_address_low_or_high mov si,di ;recover start of block or si,si jnz not_zero inc si jmps test_address_lines_joined not_zero: shl si,1 jns test_address_lines_joined jmp set_first_flag ;we've got a ram fault - stick out message and halt - note we haven't got ;a stack set up so can't call oswrch ;if not type 0 write out di/si rw_fault: sub dl,dl dec si dec si jmps ram_error address_fault: cmp al,ah ;same pattern as written ? jnz ram_error inc dl ram_error: mov cx,si ;save si in cx mov ax,rom_seg mov ds,ax mov bx,offset bad_ram emsg: mov si,bx cld emsg_loop: lodsb test al,al jz emsg_end xchg al,ah ;save al ewrch_loop: in al,r1stat shl al,1 jns ewrch_loop xchg al,ah out r1data,al jmps emsg_loop emsg_end: add dl,'0' e: in al,r1stat shl al,1 jns e mov al,dl out r1data,al mov dl,'/' f: in al,r1stat shl al,1 jns f mov al,dl out r1data,al ;entry cx contains failure address mov bx,4 ;number of digits mov al,ch upper: mov ah,al ;save lower nibble shr al, 1 shr al, 1 shr al, 1 shr al, 1 nibble: and al,0fh cmp al, 10 jb digit add al, 7 digit: add al, '0' mov dl,al g: in al,r1stat shl al,1 jns g mov al,dl out r1data,al dec bx jz halt cmp bx,2 jz do_lo_byte mov al,ah jmps nibble do_lo_byte: mov al,cl jmps upper halt: cli hlt bad_ram db lf,'Ram fault ',0 ;ok now we're going to check the refresh so start with the timers ;also tentatively set up stack - as long as any routines which use it ;take less than approx 8 ms then contents should be ok even if refresh ;is donald ducked set_up_stack: sub ax,ax mov ss,ax mov sp,offset monitor_tos test_dem_timers: ;set up timer2 to max count of 01000h mov ax,01000h mov dx,timer2_maxa out dx,ax ;reset count to zero - just in case sub ax,ax mov dx,timer2_count out dx,ax ;enable timer 2 - use count register a mov ax,0c000h ;halt when max count reached mov dx,timer2_control out dx,ax mov cx,0100h ;4 cycles delay: nop ;3 loop delay ;17 if taken 5 if not ;above delay is approx 256*20 + 9 = 5129 cycles so counters should have ;counted 5129/4 times ; mov dx,timer0_count ; in ax,dx ; mov bx,ax ; mov dx,timer1_count ; in ax,dx ; mov cx,ax ;read timer2 count mov dx,timer2_count ;4 in ax,dx ;8 ; call hexword ; call newl ; mov bx,cx ; call hexword ; call newl mov bx,ax call hexword call newl ;now enable refresh events mov ax,count ;set timer count a to &20 mov dx,timer0_maxa out dx,ax ;enable timer - use count register a - run continously mov ax,0c001h mov dx,timer0_control out dx,ax ;reset timer 2 again sub ax,ax mov dx,timer2_count out dx,ax ;and try timing loop again mov cx,0100h ;4 cycles delay1: nop ;3 loop delay1 ;17 if taken 5 if not mov dx,timer2_count in ax,dx mov bx,ax call hexword call newl ;first set up checksum bytes and set first flag set_first_flag: mov ds:byte ptr first_flag,-1 ;assumes ds still 0 mov ax,rom_seg mov ds,ax ;ds=0f000h mov si,offset neil sub ax,ax mov es,ax ;es=0 mov di,offset first mov cx,2 rep movsw jmp copy_rom org 03a6eh ;IBM compatible font for Acorn DOS series ;This is the font to be downloaded to the 6502 when required db 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H db 03EH, 041H, 055H, 041H, 055H, 05DH, 041H, 03EH db 03EH, 07FH, 06BH, 07FH, 06BH, 063H, 07FH, 03EH db 000H, 036H, 07FH, 07FH, 07FH, 03EH, 01CH, 008H db 008H, 01CH, 03EH, 07FH, 03EH, 01CH, 008H, 000H db 03EH, 03EH, 008H, 07FH, 07FH, 008H, 008H, 000H db 008H, 01CH, 03EH, 07FH, 06BH, 008H, 008H, 000H db 000H, 000H, 000H, 018H, 018H, 000H, 000H, 000H db 0FFH, 0FFH, 0E7H, 0E7H, 0FFH, 0FFH, 0FFH, 0FFH db 03EH, 063H, 063H, 063H, 063H, 063H, 03EH, 000H db 0C1H, 09CH, 09CH, 09CH, 09CH, 09CH, 0C1H, 0FFH db 03CH, 00AH, 010H, 03CH, 066H, 066H, 03CH, 000H db 000H, 03CH, 066H, 066H, 03CH, 018H, 07EH, 018H db 018H, 014H, 014H, 010H, 010H, 010H, 070H, 070H db 030H, 028H, 038H, 028H, 068H, 068H, 008H, 038H db 008H, 008H, 03EH, 022H, 063H, 03EH, 008H, 008H db 000H, 0C0H, 0F0H, 0FEH, 0F0H, 0C0H, 000H, 000H db 000H, 006H, 03EH, 0FEH, 03EH, 006H, 000H, 000H db 018H, 03CH, 05AH, 018H, 018H, 05AH, 03CH, 018H db 066H, 066H, 066H, 066H, 066H, 000H, 066H, 000H db 03EH, 052H, 052H, 03EH, 012H, 012H, 012H, 012H db 03CH, 062H, 060H, 03CH, 042H, 03CH, 006H, 03CH db 000H, 000H, 000H, 07EH, 07EH, 000H, 000H, 000H db 018H, 03CH, 05AH, 018H, 05AH, 03CH, 018H, 07EH db 018H, 03CH, 05AH, 018H, 018H, 018H, 018H, 000H db 018H, 018H, 018H, 018H, 05AH, 03CH, 018H, 000H db 000H, 008H, 00CH, 0FEH, 00CH, 008H, 000H, 000H db 000H, 020H, 060H, 0FEH, 060H, 020H, 000H, 000H db 000H, 000H, 060H, 060H, 060H, 07EH, 000H, 000H db 000H, 024H, 042H, 0FFH, 042H, 024H, 000H, 000H db 000H, 000H, 000H, 018H, 03CH, 07EH, 000H, 000H db 000H, 000H, 07EH, 03CH, 018H, 000H, 000H, 000H db 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H db 018H, 018H, 018H, 018H, 018H, 000H, 018H, 000H db 06CH, 06CH, 06CH, 000H, 000H, 000H, 000H, 000H db 036H, 036H, 07FH, 036H, 07FH, 036H, 036H, 000H db 00CH, 03FH, 068H, 03EH, 00BH, 07EH, 018H, 000H db 060H, 066H, 00CH, 018H, 030H, 066H, 006H, 000H db 038H, 06CH, 06CH, 038H, 06DH, 066H, 03BH, 000H db 00CH, 018H, 030H, 000H, 000H, 000H, 000H, 000H db 00CH, 018H, 030H, 030H, 030H, 018H, 00CH, 000H db 030H, 018H, 00CH, 00CH, 00CH, 018H, 030H, 000H db 000H, 018H, 07EH, 03CH, 07EH, 018H, 000H, 000H db 000H, 018H, 018H, 07EH, 018H, 018H, 000H, 000H db 000H, 000H, 000H, 000H, 000H, 018H, 018H, 030H db 000H, 000H, 000H, 07EH, 000H, 000H, 000H, 000H db 000H, 000H, 000H, 000H, 000H, 018H, 018H, 000H db 000H, 006H, 00CH, 018H, 030H, 060H, 000H, 000H db 03CH, 066H, 06EH, 07EH, 076H, 066H, 03CH, 000H db 018H, 038H, 018H, 018H, 018H, 018H, 07EH, 000H db 03CH, 066H, 006H, 00CH, 018H, 030H, 07EH, 000H db 03CH, 066H, 006H, 01CH, 006H, 066H, 03CH, 000H db 00CH, 01CH, 03CH, 06CH, 07EH, 00CH, 00CH, 000H db 07EH, 060H, 07CH, 006H, 006H, 066H, 03CH, 000H db 01CH, 030H, 060H, 07CH, 066H, 066H, 03CH, 000H db 07EH, 006H, 00CH, 018H, 030H, 030H, 030H, 000H db 03CH, 066H, 066H, 03CH, 066H, 066H, 03CH, 000H db 03CH, 066H, 066H, 03EH, 006H, 00CH, 038H, 000H db 000H, 000H, 018H, 018H, 000H, 018H, 018H, 000H db 000H, 000H, 018H, 018H, 000H, 018H, 018H, 030H db 00CH, 018H, 030H, 060H, 030H, 018H, 00CH, 000H db 000H, 000H, 07EH, 000H, 07EH, 000H, 000H, 000H db 030H, 018H, 00CH, 006H, 00CH, 018H, 030H, 000H db 03CH, 066H, 00CH, 018H, 018H, 000H, 018H, 000H db 03CH, 066H, 06EH, 06AH, 06EH, 060H, 03CH, 000H db 03CH, 066H, 066H, 07EH, 066H, 066H, 066H, 000H db 07CH, 066H, 066H, 07CH, 066H, 066H, 07CH, 000H db 03CH, 066H, 060H, 060H, 060H, 066H, 03CH, 000H db 078H, 06CH, 066H, 066H, 066H, 06CH, 078H, 000H db 07EH, 060H, 060H, 07CH, 060H, 060H, 07EH, 000H db 07EH, 060H, 060H, 07CH, 060H, 060H, 060H, 000H db 03CH, 066H, 060H, 06EH, 066H, 066H, 03CH, 000H db 066H, 066H, 066H, 07EH, 066H, 066H, 066H, 000H db 07EH, 018H, 018H, 018H, 018H, 018H, 07EH, 000H db 03EH, 00CH, 00CH, 00CH, 00CH, 06CH, 038H, 000H db 066H, 06CH, 078H, 070H, 078H, 06CH, 066H, 000H db 060H, 060H, 060H, 060H, 060H, 060H, 07EH, 000H db 063H, 077H, 07FH, 06BH, 06BH, 063H, 063H, 000H db 066H, 066H, 076H, 07EH, 06EH, 066H, 066H, 000H db 03CH, 066H, 066H, 066H, 066H, 066H, 03CH, 000H db 07CH, 066H, 066H, 07CH, 060H, 060H, 060H, 000H db 03CH, 066H, 066H, 066H, 06AH, 06CH, 036H, 000H db 07CH, 066H, 066H, 07CH, 06CH, 066H, 066H, 000H db 03CH, 066H, 060H, 03CH, 006H, 066H, 03CH, 000H db 07EH, 018H, 018H, 018H, 018H, 018H, 018H, 000H db 066H, 066H, 066H, 066H, 066H, 066H, 03CH, 000H db 066H, 066H, 066H, 066H, 066H, 03CH, 018H, 000H db 063H, 063H, 06BH, 06BH, 07FH, 077H, 063H, 000H db 066H, 066H, 03CH, 018H, 03CH, 066H, 066H, 000H db 066H, 066H, 066H, 03CH, 018H, 018H, 018H, 000H db 07EH, 006H, 00CH, 018H, 030H, 060H, 07EH, 000H db 07CH, 060H, 060H, 060H, 060H, 060H, 07CH, 000H db 000H, 060H, 030H, 018H, 00CH, 006H, 000H, 000H db 03EH, 006H, 006H, 006H, 006H, 006H, 03EH, 000H db 018H, 03CH, 066H, 042H, 000H, 000H, 000H, 000H db 000H, 000H, 000H, 000H, 000H, 000H, 000H, 0FFH db 01CH, 036H, 030H, 07CH, 030H, 030H, 07EH, 000H db 000H, 000H, 03CH, 006H, 03EH, 066H, 03EH, 000H db 060H, 060H, 07CH, 066H, 066H, 066H, 07CH, 000H db 000H, 000H, 03CH, 066H, 060H, 066H, 03CH, 000H db 006H, 006H, 03EH, 066H, 066H, 066H, 03EH, 000H db 000H, 000H, 03CH, 066H, 07EH, 060H, 03CH, 000H db 01CH, 030H, 030H, 07CH, 030H, 030H, 030H, 000H db 000H, 000H, 03EH, 066H, 066H, 03EH, 006H, 03CH db 060H, 060H, 07CH, 066H, 066H, 066H, 066H, 000H db 018H, 000H, 038H, 018H, 018H, 018H, 03CH, 000H db 018H, 000H, 038H, 018H, 018H, 018H, 018H, 070H db 060H, 060H, 066H, 06CH, 078H, 06CH, 066H, 000H db 038H, 018H, 018H, 018H, 018H, 018H, 03CH, 000H db 000H, 000H, 036H, 07FH, 06BH, 06BH, 063H, 000H db 000H, 000H, 07CH, 066H, 066H, 066H, 066H, 000H db 000H, 000H, 03CH, 066H, 066H, 066H, 03CH, 000H db 000H, 000H, 07CH, 066H, 066H, 07CH, 060H, 060H db 000H, 000H, 03EH, 066H, 066H, 03EH, 006H, 007H db 000H, 000H, 06CH, 076H, 060H, 060H, 060H, 000H db 000H, 000H, 03EH, 060H, 03CH, 006H, 07CH, 000H db 030H, 030H, 07CH, 030H, 030H, 030H, 01CH, 000H db 000H, 000H, 066H, 066H, 066H, 066H, 03EH, 000H db 000H, 000H, 066H, 066H, 066H, 03CH, 018H, 000H db 000H, 000H, 063H, 06BH, 06BH, 07FH, 036H, 000H db 000H, 000H, 066H, 03CH, 018H, 03CH, 066H, 000H db 000H, 000H, 066H, 066H, 066H, 03EH, 006H, 03CH db 000H, 000H, 07EH, 00CH, 018H, 030H, 07EH, 000H db 00CH, 018H, 018H, 070H, 018H, 018H, 00CH, 000H db 018H, 018H, 018H, 000H, 018H, 018H, 018H, 000H db 030H, 018H, 018H, 00EH, 018H, 018H, 030H, 000H db 031H, 06BH, 046H, 000H, 000H, 000H, 000H, 000H db 000H, 018H, 03CH, 066H, 07EH, 000H, 000H, 000H org 03e70h POWER_ON_START: push sp ;check processor type pop ax cmp ax,sp jnz not_286 mov al,12 ;set int vector out 60h,al jmp ram_test not_286: mov ax,03ff8h ;define lower memory block as mov dx,lmcs ;0 - 3ffffh i.e. 256 K out dx,ax mov ax,08238h ;define 16k block size for mid range mov dx,mpcs ;memory - 4k select size , 5 pcs out dx,ax ;lines,a1,a2 - peripherals in io space mov ax,0b9f8h ;define mid range base address as mov dx,mmcs ;b8000h - for ibm screen out dx,ax mov ax,0c038h or wait_states ;define upper memory block as mov dx,umcs ;c0000h - fffffh out dx,ax ;1 wait state mov ax,count ;set timer count a to &20 mov dx,timer0_maxa out dx,ax mov ax,0c001h ;enable timer - use count register a mov dx,timer0_control out dx,ax mov ax,003eh ;set peripheral base address to 0000h mov dx,pacs ;with 2 wait states, no external ready out dx,ax mov ax,0 ;set up int0 mov dx,int0_control out dx,ax jmp ram_test ;now copy rom from 0c000:0000 to 0000:0000 ;first copy interrupt table copy_rom: sub ax,ax mov si,ax ;source offset = 0 mov di,ax ;dest offset = 0 mov es,ax ;dest segment = 0 mov ax,0c000h mov ds,ax ;source segment = 0c000h mov cx,0200h ;copy interrupt table rep movsw ;now copy rest of rom - leaving some non corrupted ram in between mov si,rom_base mov di,si mov cx,(rom_size-rom_base)/2 rep movsw db 0eah ;jump long to ram copy in segment 0 dw code_start,0 org 03ff0h db 0eah dw 0c000h+offset POWER_ON_START,0f000h db '11/08/82',0ffh,0feh,027h ;I'm an XT - honest ! end