;**************************************************************************** ; ; Atari 400/800 emulator startup code ; ; Acknowldgements: This code is based on the code written for the Apple ; emulator by Randy W. Spurlock. ; ; ;**************************************************************************** ; ; Public Declarations ; Public Initialize ; Atari emulator initialization routine ; Public Read_Memory ; Read 65C02 memory routine Public Write_Memory ; Write 65C02 memory routine Public System_Request ; System request routine (Req.) Public System_Access ; Atari system reset routine (Req.) Public Access ; access IBM dos Public Error ; Atari emulator error routine Public Exit ; Atari emulator exit routine Public filenum1 Public filenum2 ; ; External Declarations ; Extrn Atari_Reset:Near Extrn Video_TEXT_OPEN:Near Extrn Jsr_Steal:Near Extrn Key_Reset:Near Extrn Int_Reset:Near Extrn Write_Hardware:Near ; Writes to hardware registers (HARDWARE) Extrn Clear_Memory:Near ; Clear memory routine (MEMORY) Extrn Video_Init:Near ; Video initialization routine (VIDEO) Extrn Video_Reset:Near ; Video reset routine (VIDEO) Extrn CPU_Reset:Near ; CPU reset routine (RESET) Extrn Set_LED:Near ; Set keyboard LED routine (KEYBOARD) Extrn Flush_Keyboard:Near ; Flush keyboard routine (KEYBOARD) Extrn Check_Key:Near ; Check for input routine (KEYBOARD) Extrn Get_Key:Near ; Get keyboard code routine (KEYBOARD) Extrn STD_Mem_Read:Near ; (Memory.asm) Extrn STD_Mem_Write:Near ; (Memory.asm) Extrn Int_Init:Near Extrn System_Address Extrn System_Size Extrn Error_Table:Word ; Error string table (DATA) Extrn System_ROM:Word ; Atari system ROM file name (DATA) Extrn Read_Table:Word ; Read memory page table (DATA) Extrn Write_Table:Word ; Write memory page table (DATA) Extrn System_Flag:Byte ; Atari emulator system flag byte(DATA) Extrn Emulate_Flag:Byte ; Emulator system flag byte (DATA) Extrn RAM_Space:Word ; RAM space segment value (DATA) Extrn ALT_Space:Word ; Alternate RAM space segment (DATA) Extrn ERR_NO_MEMORY:Abs ; Not enough memory error code (DATA) Extrn ERR_NO_SYSTEM_FILE:Abs ; No system ROM file error code (DATA) Extrn ERR_BAD_SYSTEM_FILE:Abs ; Bad system ROM file error code (DATA) Extrn ERR_BAD_SYSTEM_IMAGE:abs; Bad system ROM image error code(DATA) Extrn Flag_Encode:Byte Extrn int_flag:Byte Extrn nmi_flag:Byte Extrn Access_flag:Byte Extrn sBOT:Word Extrn sTOP:Word ; ; LOCAL Equates ; BREAK_OFFSET Equ 02h ; Breakpoint match offset value SYSTEM_TOP Equ 0e000h ; ; Define any include files needed ; Include Macros.inc ; Include the macro definitions Include Equates.inc ; Include the equate definitions Include Strucs.inc ; Include the structure definitions Include Atari.inc .286c ; Include 80286 instructions Page ; ; Define the emulator code segment ; Emulate Segment Word Public 'EMULATE' ; Emulator code segment Assume cs:Emulate, ds:Nothing, es:Nothing Subttl Load_System Load the Atari System ROM Page + ;****************************************************************************** ; ; Load_System(RAM_Space) ; ; Save the required registers ; Try to open the Atari System ROM data file ; If no errors opening the System ROM file ; Try to read in the System ROM image ; If errors reading the System ROM ; Set error code to bad System ROM file ; Call the error routine ; Call routine to exit the emulator ; Endif ; Close the System ROM file ; Else errors opening the System ROM file ; Set error code to no System ROM file ; Call the error routine ; Call routine to exit the emulator ; Endif ; Restore the required registers ; Return to the caller ; ; Registers on Entry: ; ; DS - 65C02 RAM space ; ; Registers on Exit: ; ; AX-DX - Destroyed ; SI-DI - Destroyed ; ;****************************************************************************** Even ; Force procedure to even address Load_System Proc Near ; Load System ROM procedure Save es ; Save the required registers mov ax,cs ; Get the current code segment value mov bx,ds ; Save 65C02 RAM space segment value mov ds,ax ; Setup to open the system ROM file mov ah,OPEN_FILE ; Get the open file function code mov al,READ_ONLY ; Get the read file access code lea dx,cs:[System_ROM] ; Get pointer to system ROM file name int DOS ; Try to open the system ROM file jnc Read_System_ROM ; Jump if no errors opening file mov al,ERR_NO_SYSTEM_FILE ; Get no system ROM file error code System_ROM_Error: call Error ; Call routine to print the error call Exit ; Call routine to exit emulator Read_System_ROM: mov ds,bx ; Restore 65C02 RAM space segment value mov bx,ax ; Move file handle to BX register mov ah,READ_FILE ; Get read file function code mov dx,SYSTEM_TOP ; Setup the data buffer address mov cx,0006h ; Read 6 byte header int DOS ; Try to read the system ROM image mov cx,ax ; Save ROM image size in CX register mov al,ERR_BAD_SYSTEM_FILE ; Get bad system ROM file error code jc System_ROM_Error ; Jump if error trying to read the file cmp cx,0006h ; Header read in? mov al,ERR_BAD_SYSTEM_IMAGE ; Bad system ROM error code jne System_ROM_Error ; Jump if header corrupted mov di,SYSTEM_TOP mov cx,[di] cmp cx,0ffffh ; Header read in? mov al,ERR_BAD_SYSTEM_IMAGE ; Bad system ROM error code jne System_ROM_Error ; Jump if header corrupted mov dx,[di + 2] ; get starting address for rom mov cx,[di + 4] ; Get ending address ... sub cx,[di + 2] ; less starting address inc cx ; add 1 to get total byte count mov di,cx ; save for compare mov ah,READ_FILE ; Get read file function code int DOS ; Try to read the system ROM image jc System_ROM_Error ; Jump if error trying to read the file cmp cx,di ; Check for all of image read in mov al,ERR_BAD_SYSTEM_IMAGE ; Get bad system ROM image error code jne System_ROM_Error ; Jump if part of image missing mov ah,CLOSE_FILE ; Get close file function code int DOS ; Close the system ROM file Restore es ; Restore the required registers ret ; Return to the caller Load_System Endp ; End of the Load_System procedure Subttl Initialize Initialize the Atari Emulator Page + ;****************************************************************************** ; ; Initialize() ; ; Clear direction flag so that "lodsb" can be used to ; increment program counter. ; Try to allocate the 65C02 RAM space (64k) ; If able to allocate the RAM space ; Setup the Atari hardware and ROM memory areas ; Call routine to load the Atari system ROM ; Call routine to handle Atari configuration ; Clear the Atari ][ system RAM area ; Call routine to initialize interrupts ; Call routine to initialize video system ; Call routine to initilize keyboard LED's ; Try to allocate the alternate 65C02 RAM space (64k) ; If able to allocate the RAM space ; Save the alternate RAM space segment ; Call routine to initialize memory ; Call routine to setup 65C02 registers (Reset) ; Else unable to allocate the needed RAM space ; Set error code to not enough memory ; Call the error routine ; Call routine to exit the emulator ; Endif ; Else unable to allocate the needed RAM space ; Set error code to not enough memory ; Call the error routine ; Call routine to exit the emulator ; Endif ; Return to the caller ; ; Registers on Entry: ; ; None ; ; Registers on Exit: ; ; DL - Accumulator initialized (0h) ; DH - 65C02 flags initialized (0h) ; CL - Y index register initialized (0h) ; CH - X index register initialized (0h) ; BX - Stack pointer initialized (1FFh) ; SI - Program counter initialized (FFFCh) ; DS - 65C02 RAM space ; ES - Video RAM segment ; ;****************************************************************************** Even ; Force procedure to even address Initialize Proc Near ; Emulator initialization procedure cld ; Clear direction flag (All forward) ;Release all memory except the amount currently being used ;End of stack is end of non-heap portion of program MOV BX,SP ADD BX,15 ;convert SP into paragraphs SHR BX,4 MOV AX,SS ;calculate size of program using ES PSP address ADD BX,AX MOV AX,ES SUB BX,AX MOV AH,4AH ; resize memory block with PSP INT 21H ; address in ES mov ah,ALLOCATE_MEMORY ; Get the allocate memory function code mov bx,RAM_SIZE ; Get number of paragraphs to allocate int DOS ; Try to allocate the 65C02 RAM space jnc Continue ; Jump if no errors allocating space Memory_Error: mov al,ERR_NO_MEMORY ; Get not enough memory error code call Error ; Call routine to print the error call Exit ; Call routine to exit the emulator Continue: mov ds,ax ; Setup RAM space segment address mov cs:[RAM_Space],ax ; Save the RAM space segment address ;IFDEF ATARI_130XE ;Need shadow ram hook for 130xe mov ah,ALLOCATE_MEMORY ; Get the allocate memory function code mov bx,RAM_SIZE ; Get number of paragraphs to allocate int DOS ; Try to allocate the 65C02 RAM space jc Memory_Error ; Jump if errors allocating space mov cs:[ALT_Space],ax ; Save alternate RAM space segment mov ds,ax ; Setup alternate RAM space segment ;ENDIF ;clear memory from 0000h to c000h mov ds,cs:[RAM_Space] ; Setup alternate 65C02 RAM segment mov si,RAM_Area ; Get pointer to start of RAM area mov cx, Size RAM_Area ; Get the number of bytes in RAM area call Clear_Memory ; Call routine to clear the memory call Load_System ; Call routine to load system ROM ;IFDEF ATARI_130XE mov ds,cs:[ALT_Space] ; Setup alternate 65C02 RAM segment mov es,cs:[RAM_Space] ; Setup the 65C02 RAM space segment mov cx,2000h ; mov 8192 bytes mov di,0a000h Basic_copy_loop: mov al,es:[di] mov ds:[di],al inc di dec cx jne Basic_copy_loop mov ds,cs:[RAM_Space] ; Setup the 65C02 RAM space segment ;ENDIF ;used to replace int 3,8,9 with own routines call Int_Init ; Call routine to initialize interrupts call Video_Init ; Call routine to initialize video call Set_LED ; Call routine to initialize LED's call CPU_Reset ; Call routine to reset the 65C02 ret ; Return to the caller Initialize Endp ; End of the Initialize procedure Subttl Error Emulator Error Routine Page + ;****************************************************************************** ; ; Error(Error_Code) ; ; Save the required registers ; Print the correct error message ; Restore the required registers ; Return to the caller ; ; Registers on Entry: ; ; AL - Error code ; ; Registers on Exit: ; ; AX-DX - Destroyed ; ;****************************************************************************** Even ; Force procedure to even address Error Proc Near ; Emulator error procedure Save ds ; Save the required registers xor ah,ah ; Convert error code to full word shl ax,1 ; Convert error code to table index mov bx,ax ; Move table index into BX register mov si,cs:[bx+Error_Table] ; Get the error string address mov ax,cs ; Get current CS register value mov ds,ax ; Setup to access the error string mov ah,WRITE_FILE ; Get write file function code mov bx,STD_ERROR ; Get the standard error handle lodsb ; Get the length of the error string mov cl,al ; Move string length into CL register xor ch,ch ; Convert string length into full word mov dx,si ; Setup error string address int DOS ; Print the error string to handle Restore ds ; Restore the required registers ret ; Return to the caller Error Endp ; End of the Error procedure Subttl Exit Emulator Exit Routine Page + ;****************************************************************************** ; ; Exit() ; ; Call routine to reset interrupt vectors ; Call routine to reset video ; Call routine to reset keyboard ; Zero the return code ; Exit to DOS ; ; Registers on Entry: ; ; None ; ; Registers on Exit: ; ; None ; ;****************************************************************************** Even ; Force procedure to even address Exit Proc Near ; Emulator exit procedure call Int_Reset ; Call the interrupt reset routine call Video_Reset ; Call the video reset routine call Key_Reset ; Call the keyboard reset routine mov ah,TERMINATE ; Get the terminate function code xor al,al ; Zero the return code int DOS ; Return control to MS-DOS ret ; Return to the caller (Never executed) Exit Endp ; End of the Exit procedure Subttl Read_Memory Read 65C02 Atari Memory Routine Page + ;****************************************************************************** ; ; Read_Memory(Effective_Address) ; ; Get the memory page from effective address ; Jump to correct routine to process read ; ; Registers on Entry: ; ; DS:DI - 65C02 Effective address ; ; Registers on Exit: ; ; AL - 65C02 Memory value ; BP - Destroyed ; ;****************************************************************************** ; Even ; Force procedure to even address ;Read_Memory Proc Near ; Read 65C02 Atari memory procedure ; call STD_Mem_Read ; mov al,ds:[di] ; Read the memory location ; ret ; Return to the caller (Never executed) ;Read_Memory Endp ; End of the Read_Memory procedure Subttl Write_Memory Write 65C02 Atari Memory Routine Page + ;****************************************************************************** ; ; Write_Memory(Effective_Address, Data_Value) ; ; Get the memory page from effective address ; Jump to correct routine to process write ; ; Registers on Entry: ; ; DS:DI - 65C02 Effective address ; AL - 65C02 Memory value ; ; Registers on Exit: ; ; AX - Destroyed ; DI - Destroyed ; BP - Destroyed ; ;****************************************************************************** Even ; Force procedure to even address Write_Memory Proc Near ; Write 65C02 Atari memory procedure mov bx,di ; Get the effective address shr bx,11 ; Get page number into AX register shl bx,1 jmp cs:[ROM_Table+bx] ; ret ; Return to the caller (Never executed) Write_Memory Endp ; End of the Write_Memory procedure Subttl System_Request Emulator System Request Routine (Request) Page + ;****************************************************************************** ; ; System_Request(Scan_Code) ; ; If this is a make code ; If not already in the system ; Set system request interrupt type ; Endif ; Endif this is a break code ; Return control to the caller ; ; Registers on Entry: ; ; AH - Scan code ; ; Registers on Exit: ; ; None ; ;****************************************************************************** Even ; Force procedure to even address System_Request Proc Near ; Emulator system request procedure or ah,ah ; Check for a make or break code js Request_Done ; Jump if this is a break code ; test cs:[Emulate_Flag],SYS_REQUEST mov di,POKMSK test Byte Ptr [di],B7 je Request_Done ; Jump if already in system procedure ;; or cs:[Emulate_Flag],SYS_REQUEST mov di,IRQST or Byte Ptr [di],B7 mov int_flag,1 Request_Done: ret ; Return to the caller System_Request Endp ; End of the System_Request procedure ;****************************************************************************** ; ; System_Access(Scan_Code) ; ; Registers on Entry: ; ; AH - Scan code ; ; Registers on Exit: ; ; None ; ;****************************************************************************** Even ; Force procedure to even address System_Access Proc Near ; Access Dos mov cs:Access_flag,1 ret System_Access Endp ; End of the System_Access procedure ;******************* ; local marcos ;******************* print macro str mov ah,9 mov dx,offset str int DOS endm set_cursor macro row,col mov ah,2 ; set cursor mov bh,0 ; set zero page mov dh,row ; set row mov dl,col ; col int 10h ; call video services endm get_key macro mov ah,0 ; wait for key strike int 16h endm get_string macro buf,len mov ah,0ah ; get string mov dx,offset buf mov di,dx mov Byte Ptr ds:[di],len int DOS endm Cur_Stat DB 'The current emulator status is:',0ah,0dh,'$' Stat1 DB 'D1: $',0,0 filenum1 DB '$', 79d DUP (0) newline DB 0ah,0dh,'$' Stat2 DB 'D2: $',0,0 filenum2 DB '$', 79d DUP (0) Stat3 DB 'Basic is $' Stat_ON DB 'ON',0ah,0dh,'$' Stat_OFF DB 'OFF',0ah,0dh,'$' CMD_MESS DB 'Enter the number of the desired command:',0ah,0dh,'$' Menu1 DB '1 - change the file for D1:',0ah,0dh,'$' Menu2 DB '2 - change the file for D2:',0ah,0dh,'$' Menu3 DB '3 - Load cartridge (not working)',0ah,0dh,'$' Menu4 DB '4 - Toggle Basic',0ah,0dh,'$' Menu5 DB '5 - Exit',0ah,0dh,'$' File_Name_Mess DB 'Please enter the filename:',0ah,0dh,'$' ;****************************************************************************** ; ; Access ; ; Registers on Entry: ; ; ; Registers on Exit: ; ; None ; ;****************************************************************************** Even ; Force procedure to even address Access Proc Near ; Access Dos pusha ; save everything call Int_Reset ; restore vectors push ds mov ax,cs ; Get current CS register value mov ds,ax ; Setup to access the error string Display: call Video_TEXT_OPEN ; open text screen set_cursor 3,0 print Cur_Stat print Stat1 print filenum1 print newline print Stat2 print filenum2 print newline print Stat3 test basic_flag,1 je Basic_is_off print Stat_ON jmp Pr_Menu Basic_is_off: print Stat_OFF Pr_Menu: set_cursor 10,0 print Menu1 print Menu2 print Menu3 print Menu4 print Menu5 print CMD_MESS get_key ; gets current keystroke into al cmp al,'5' jne Test_D1 jmp Access_Done Test_D1: cmp al,'1' jne Test_D2 print File_Name_Mess get_string filenum1-2,80d mov al,[filenum1-1] xor ah,ah mov di,ax mov [filenum1+di],'$' jmp Display Test_D2: cmp al,'2' jne Test_B print File_Name_Mess get_string filenum2-2,80d mov al,[filenum2-1] xor ah,ah mov di,ax mov [filenum2+di],'$' jmp Display Test_B: cmp al,'4' je Basic_Toggle jmp Display Basic_Toggle: test basic_flag,1 ; is basic already on? je Turn_Basic_ON ; jmp if not already on mov di,offset ROM_Table ; add di,40d mov Word Ptr [di],offset STD_Mem_Write ;allow write to ram mov Word Ptr [di+2],offset STD_Mem_Write mov Word Ptr [di+4],offset STD_Mem_Write mov Word Ptr [di+6],offset STD_Mem_Write mov basic_flag,0 ; reset basic on flag pop ds ; get atari ram segment push ds ; save back call Atari_Reset ; reset atari mov ax,cs ; mov ds,ax ; ds = cs jmp Display Turn_Basic_ON: mov di,offset ROM_Table add di,40d mov Word Ptr [di],offset ROM_Write ; write protect ram space mov Word Ptr [di+2],offset ROM_Write mov Word Ptr [di+4],offset ROM_Write mov Word Ptr [di+6],offset ROM_Write mov cx,2000h ; mov 8192 bytes mov di,0a000h ; mov data to cart. area pop ds ; get atari ram space push ds ; save back push es ; save video pointer mov es,cs:[ALT_Space] ; get alt. ram space Copy_Basic_Loop: mov al,es:[di] ; get basic rom code mov [di],al ; save basic rom code in atari ram inc di ; next byte dec cx ; dec. byte counter jne Copy_Basic_Loop pop es ; get back video segment mov basic_flag,1 ; set basic on flag call Atari_Reset ; reset atari mov ax,cs ; mov ds,ax ; make ds=cs jmp Display ; reprint menu Access_Done: pop ds ; get atari ram segment call Video_Init ; get atari display mov cs:Access_flag,0 ; reset command access flag call Int_Init ; restore vectors popa ret Access Endp ; End of the System_Access procedure ;****************************************************************************** ; ; ROM_Write ; ; Registers on Entry: ; ; None ; ; Registers on Exit: ; ; None ; ;****************************************************************************** Even ; Force procedure to even address ROM_Write Proc Near ; ret ROM_Write Endp ; End of the System_Access procedure ;****************************************************************************** ; ; Define the RAM/ROM/Hardware write table ; This table can be changed by the user. ;****************************************************************************** ROM_Table Equ This Word DW STD_Mem_Write ; 0000 DW STD_Mem_Write ; 0800 DW STD_Mem_Write ; 1000 DW STD_Mem_Write ; 1800 DW STD_Mem_Write ; 2000 DW STD_Mem_Write ; 2800 DW STD_Mem_Write ; 3000 DW STD_Mem_Write ; 3800 DW STD_Mem_Write ; 4000 DW STD_Mem_Write ; 4800 DW STD_Mem_Write ; 5000 DW STD_Mem_Write ; 5800 DW STD_Mem_Write ; 6000 DW STD_Mem_Write ; 6800 DW STD_Mem_Write ; 7000 DW STD_Mem_Write ; 7800 DW STD_Mem_Write ; 8000 DW STD_Mem_Write ; 8800 DW STD_Mem_Write ; 9000 DW STD_Mem_Write ; 9800 DW ROM_Write ; a000 DW ROM_Write ; a800 DW ROM_Write ; b000 DW ROM_Write ; b800 DW STD_Mem_Write ; c000 DW STD_Mem_Write ; c800 DW Write_Hardware ; d000 DW ROM_Write ; d800 DW ROM_Write ; e000 DW ROM_Write ; e800 DW ROM_Write ; f000 DW ROM_Write ; f800 basic_flag DB 1 ;****************************************************************************** ; ; Define the end of the Emulator Code Segment ; ;****************************************************************************** Emulate Ends End ; End of the Atari module