; Galaksija 8k-54k Emulator wit RAZE.DLL
Enumeration
   #AF
   #BC
   #DE
   #HL
   #IX
   #IY
   #PC
   #SP
   #AF2
   #BC2
   #DE2
   #HL2
   #IFF1
   #IFF2
   #IR
   #IM
   #IRQV
   #IRQL
   #HALT
   #Z80_MAP_DIRECT=0  ; Reads/writes are done directly
   #Z80_MAP_HANDLED=1  ;Reads/writes use a function handler
   #GTP_BLOCK_STANDARD=0
   #GTP_BLOCK_TURBO=1
   #GTP_BLOCK_NAME=16
EndEnumeration
Structure dos ; 8268 byte
  _AF.l
  _BC.l
  _DE.l
  _HL.l
  _IX.l
  _IY.l
  _PC.l
  _SP.l
  _AF2.l
  _BC2.l
  _DE2.l
  _HL2.l
  _IFF.l
  _IFF1.l
  _IFF2.l
  _IM.l
  _I.l
  _IRQVec.l
  _R.l
EndStructure
Structure win ; 8244 byte
  _AF.w
  _BC.w
  _DE.w
  _HL.w
  _IX.w
  _IY.w
  _PC.w
  _SP.w
  _AF2.w
  _BC2.w
  _DE2.w
  _HL2.w
  _IM.c
  _I.c
  _R.c
  _unk.c[25]
EndStructure
Structure gmap
 code.i[54]
EndStructure

Global tstate.l, z80.l, set.l=1, err.l=1, ext.l=2, mmu.q, from.b, fram.b, pnum.l, pname.s
Global Dim mem.c(65536)
Global Dim inout.c(65536)
Global *rom1=@mem(), *rom2=*rom1+4096, *kb_io=*rom2+4096, *g_scr=*kb_io+2048
Global *rom3=*rom1+$e000 : *mon=*rom3+6144 : *kb.gmap=?KBMAP

ProcedureC.c inproc(adr.u)
 ProcedureReturn inout(adr)
EndProcedure

ProcedureC outproc(adr.u,num.c)
  inout(adr)=num
  If (adr&255=255) And IsFile(8)
    If num<>13
      WriteCharacter(8,num)
    Else
      WriteStringN(8,"",#PB_Ascii)
    EndIf
   EndIf
EndProcedure

ProcedureC ear(adr.u,num.c)
If adr=$2038
  SoundVolume(0,50)
  If num=$fc
    SetSoundFrequency(0,660)
  ElseIf num=$b8
    SetSoundFrequency(0,400)
  ElseIf num=$bc
    SoundVolume(0,0)
  EndIf
Else
  mem(adr)=num
EndIf
EndProcedure

Procedure Calc(z.q)
  Shared from, fram
  For i=0 To 15
   from+((z&1)*2) : z>>1
  Next i
  fram=62-from
EndProcedure

CatchImage(256,?gchset,?ROM_A-?gchset,#PB_Image_DisplayFormat) : mmu=0
For i=0 To 255 : GrabImage(256,i,i*8,0,8,13) : Next i
CopyMemory(?ROM_A,*rom1,?ROM_B-?ROM_A) : mmu|%11
CopyMemory(?ROM_B,*rom2,?ROM_C-?ROM_B) : mmu|%1100
;CopyMemory(?ROM_C,*rom1+$e000,?MONITOR-?ROM_C) : mmu|$30000000
If mmu&12 : mmu|$80000000 : EndIf ; Monitor only works if ROM2 present
If mmu&$30000000
  PokeL(*rom1+$3f8,$e000c4e5) : PokeB(*rom1+$37,30) ; patch for ROM2 + ROM3 init & ROM version
ElseIf mmu&12
  PokeL(*rom1+$3f8,$1000c4e5) : PokeB(*rom1+$37,29) ; patch for ROM2 init & ROM version
Else
  PokeL(*rom1+$3f8,$e70c3ee5) : PokeB(*rom1+$37,28) ; patch for ROM1 only init & ROM version
EndIf 
Calc(mmu)
r$="Galaksija "+Str(from)+"K-"+Str(fram)+"K"
UsePNGImageDecoder()
If OpenWindow(0, -1, -1, 720, 495, "Galaksija Minus", #PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget)
  ButtonGadget(0, 660, 10, 45, 20, "Quit")
  ButtonGadget(1, 660, 40, 45, 20, "NMI")
  ButtonGadget(2, 660, 65, 45, 20, "RESET")
  ButtonGadget(3, 660, 100, 45, 20, "Load")
  ButtonGadget(4, 660, 125, 45, 20, "Save")
  ButtonGadget(5,660,160,45,20,"Options")
  ButtonGadget(6,660,185,45,20,"Help")
  ButtonGadget(8,660,210,45,5,"") : HideGadget(8,1)
  CheckBoxGadget(7,645,230,72,20,"Printer ON") 
  AddKeyboardShortcut(0, #PB_Shortcut_F1,  #PB_Shortcut_F1)    ; Help
  AddKeyboardShortcut(0, #PB_Shortcut_F2,  #PB_Shortcut_F2)    ; Save
  AddKeyboardShortcut(0, #PB_Shortcut_F3,  #PB_Shortcut_F3)    ; Load
  AddKeyboardShortcut(0, #PB_Shortcut_F9,  #PB_Shortcut_F9)    ; NMI (RST &66)
  AddKeyboardShortcut(0, #PB_Shortcut_F10,  #PB_Shortcut_F10)  ; Reset Z80
  AddKeyboardShortcut(0, #PB_Shortcut_F12,  #PB_Shortcut_F12)  ; Options
    If CreateStatusBar(0, WindowID(0))
      AddStatusBarField(#PB_Ignore) ; autosize this field
      StatusBarText(0, 0, r$)
    EndIf
  For x=0 To 2047 : mem($2000+x)=255 : Next x
  If InitSprite() And OpenWindowedScreen(WindowID(0), 0, 0, 313, 224, 1, 94, 23) And InitKeyboard() And InitSound()
    SetFrameRate(50) : SmartWindowRefresh(0, 1) : WindowBounds(0, 407, 240, #PB_Ignore, #PB_Ignore)
    SetWindowColor(0,0)
    CatchSound(0,?WAV) : PlaySound(0,#PB_Sound_Loop) : SoundVolume(0,0)
    If OpenLibrary(z80,"raze.dll")
    *z80_init_memmap=GetFunction(z80,"_z80_init_memmap")
    *z80_map_fetch=GetFunction(z80,"_z80_map_fetch")
    *z80_add_read=GetFunction(z80,"_z80_add_read")
    *z80_add_write=GetFunction(z80,"_z80_add_write")
    *z80_set_in=GetFunction(z80,"_z80_set_in")
    *z80_set_out=GetFunction(z80,"_z80_set_out")
    *z80_end_memmap=GetFunction(z80,"_z80_end_memmap")
    *z80_reset=GetFunction(z80,"_z80_reset")
    *z80_cause_NMI=GetFunction(z80,"_z80_cause_NMI")
    *z80_get_context_size=GetFunction(z80,"_z80_get_context_size")
    *z80_get_context=GetFunction(z80,"_z80_get_context")
    *z80_set_context=GetFunction(z80,"_z80_set_context")
    *z80_get_reg=GetFunction(z80,"_z80_get_reg")
    *z80_set_reg=GetFunction(z80,"_z80_set_reg")
    *z80_emulate=GetFunction(z80,"_z80_emulate")
    *z80_raise_IRQ=GetFunction(z80,"_z80_raise_IRQ")
    *z80_lower_IRQ=GetFunction(z80,"_z80_lower_IRQ")
    *z80_fetch_callback=GetFunction(z80,"_z80_set_fetch_callback")
    CallCFunctionFast(*z80_init_memmap)
    CallCFunctionFast(*z80_map_fetch,0, $ffff, *rom1)      ; Allow opcodes To be fetched from LOW ROM/RAM
    CallCFunctionFast(*z80_add_read,0, $ffff, #Z80_MAP_DIRECT, *rom1)      ; Allow reads from ROM/RAM
    ;CallCFunctionFast(*z80_add_write,$2000, $27ff, #Z80_MAP_HANDLED, @ear()) ; Handle Latch/KBoard writes
    If mmu&$80000000 
      CopyMemory(?MONITOR,*rom3+$1800,?KBMAP-?MONITOR)      ; Allow opcodes To be fetched from MONITOR ROM
      CallCFunctionFast(*z80_add_write,$2000, $f7ff, #Z80_MAP_DIRECT, *kb_io) ; Don't allow ROM writes, but allow RAM writes
    Else
      CallCFunctionFast(*z80_map_fetch,$f800, $ffff, *mon)      ; Allow opcodes To be fetched from HIGH RAM
      CallCFunctionFast(*z80_add_write,$2000, $ffff, #Z80_MAP_DIRECT, *kb_io) ; Don't allow ROM writes, but allow RAM writes
    EndIf
      CallCFunctionFast(*z80_set_in,@inproc())    ; recommended for ROM2/48K (Printer, AY Sound etc.)
      CallCFunctionFast(*z80_set_out,@outproc())    ; recommended for ROM2/48K (Printer, AY Sound etc.)
     CallCFunctionFast(*z80_end_memmap)
     CallCFunctionFast(*z80_reset) ; reset the CPU
     ;CallCFunctionFast(*z80_fetch_callback,@GLoad())   ; very slow !!!
       snap_size.l=CallCFunctionFast(*z80_get_context_size)
       *snap_adr=ReAllocateMemory(*snap_adr,snap_size)
       If *snap_adr
         CallCFunctionFast(*z80_get_context,*snap_adr)
       Else
         MessageRequester("Error","Memory allocation failed!",0)
       EndIf
     Else
       MessageRequester("Error", "Can't find Z80 core!", 0)
       End
     EndIf
  Else
     MessageRequester("Error", "Can't open windowed screen!", 0)
     End
  EndIf
    Repeat
      Event = WindowEvent()
      Select Event 
        Case #PB_Event_Gadget
          Select EventGadget()
          Case 0
            End
          Case 1
            CallCFunctionFast(*z80_cause_NMI)
          Case 2
            CallCFunctionFast(*z80_reset) : StatusBarText(0, 0, r$)
          Case 3
            Gosub Load
          Case 4
            Gosub Save
          Case 5
          Case 6
          Case 7
            If GetGadgetState(7)
              pname=OpenFileRequester("Print spooler",pname,"Text file (*.txt)|*.txt",0)
              If pname<>"" And OpenFile(8,pname,#PB_File_SharedWrite|#PB_File_Append)
                SetActiveGadget(8) : SetGadgetText(7,"Printer OFF")
              Else
                SetGadgetState(7,#PB_Checkbox_Unchecked) : SetActiveGadget(8) : SetGadgetText(7,"Printer ON")
                MessageRequester("Error","File open error, or\nRequester canceled!",0)
              EndIf
            Else
              CloseFile(8) : SetActiveGadget(8) : SetGadgetText(7,"Printer ON")
            EndIf
          EndSelect
        Case #PB_Event_Menu
          Select EventMenu()
          Case  #PB_Shortcut_F1
          Case  #PB_Shortcut_F2
            Gosub Save
          Case  #PB_Shortcut_F3
            Gosub Load
          Case  #PB_Shortcut_F9
            CallCFunctionFast(*z80_cause_NMI)
          Case  #PB_Shortcut_F10
            CallCFunctionFast(*z80_reset) : StatusBarText(0, 0, r$)
          Case  #PB_Shortcut_F12
          EndSelect
        Case #PB_Event_CloseWindow
          End 
        Case #PB_Event_SizeWindow ;window is resized
         ww.l=WindowWidth(0) : wh.l=ww/1.4545454545
         ResizeWindow(0,#PB_Ignore,#PB_Ignore,ww,wh)
         ResizeGadget(0, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(1, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(2, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(3, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(4, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(5, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(6, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
         ResizeGadget(7, ww-75, WindowHeight(0)-47, #PB_Ignore, #PB_Ignore)
         ResizeGadget(8, ww-60, #PB_Ignore, #PB_Ignore, #PB_Ignore)
       Case #PB_Event_WindowDrop ; text , data or picture dropped on window
       Case #PB_Event_Timer ; draw galaksija screen?
      EndSelect
    ExamineKeyboard()
    If KeyboardPushed(#PB_Key_All)
      For i=1 To 53
        If KeyboardPushed(*kb\code[i]) : mem($2000+i)&254 : EndIf
      Next i
      If KeyboardPushed(#PB_Key_Back) : mem($201d)&254 : EndIf ;LEFT <- (same as left)
      If KeyboardPushed(#PB_Key_LeftShift) : mem($2035)&254 : EndIf ;Left_SHIFT
      If KeyboardPushed(#PB_Key_Home) : mem($2035)&254: mem($2033)&254 : EndIf ;HOME (shift+del)
    EndIf
    CallCFunctionFast(*z80_emulate,3072000/500)
    If tstate=0
      FlipBuffers() 
      ClearScreen(0)
      If CallCFunctionFast(*z80_get_reg,#IFF1)
        SoundVolume(0,0) : StartDrawing(ScreenOutput())
        vscrol.l=(mem($2bb0)*3)+8 : hpos=(mem($2ba8)*8)-64 : mpp=$2800
        For i=0 To 195 Step 13
          For j=0 To 248 Step 8
            DrawImage(ImageID(mem(mpp)),hpos+j,vscrol+i) : mpp+1
          Next j
        Next i
        Box(0,216,313,8,0)
        StopDrawing()
      Else
        com.l=mem($2bb6)<<24 | mem($2bb7)<<16|mem($2bb8)<<8|mem($2bb9)
        If com=$53415645
          SoundVolume(0,50) ; Fake Save sound
        EndIf
      EndIf
      CallCFunctionFast(*z80_raise_IRQ,255)
      CallCFunctionFast(*z80_lower_IRQ)
     For i=1 To 53 : mem($2000+i)|1 : Next i
      tstate=10
    EndIf
    tstate-1
  ForEver

CloseLibrary(0)
  End
EndIf

Load:
      f$=OpenFileRequester("Select Galaksija file to load","","Tape (*.gtp)|*.gtp|GAL Snapshot (*.gal)|*.gal|Raze snapshot (*.grz)|*.grz",ext)
      If f$ And ReadFile(4,f$)
      flen=Lof(4)
      ext=SelectedFilePattern()
      Select ext
      Case 0 ; gtp - multi block load
      bcn.c=0
      While Eof(4)=0
        Select ReadByte(4)
          Case 0,1 ; normal & turbo block
            len.l=ReadLong(4)
            hdr.c=ReadByte(4)
            lstart.w=ReadWord(4)
            lend.w=ReadWord(4)
            ReadData(4,*rom1+lstart,lend-lstart)
            crc.w=ReadWord(4)
            If Loc(4)<flen : bcn+1 : Continue : EndIf
            CallCFunctionFast(*z80_set_reg,#PC,$317) : Break ; prints "<>READY" to screen !?
          Case 16 ; name block
             len.l=ReadLong(4) : f$+" "+StrU(bcn)+". "+Space(len)
             ReadData(4,@f$+(Len(f$)-len),len)
         EndSelect
       Wend
       Case 1 ; gal snapshot
       If flen=8268 ;dos
         ReadData(4,@dhead.dos,76)
         ReadData(4,*kb_io,8192)
         CallCFunctionFast(*z80_set_reg,#AF,dhead\_AF)
         CallCFunctionFast(*z80_set_reg,#BC,dhead\_BC)
         CallCFunctionFast(*z80_set_reg,#DE,dhead\_DE)
         CallCFunctionFast(*z80_set_reg,#HL,dhead\_HL)
         CallCFunctionFast(*z80_set_reg,#IX,dhead\_IX)
         CallCFunctionFast(*z80_set_reg,#IY,dhead\_IY)
         CallCFunctionFast(*z80_set_reg,#PC,dhead\_PC)
         CallCFunctionFast(*z80_set_reg,#SP,dhead\_SP)
         CallCFunctionFast(*z80_set_reg,#AF2,dhead\_AF2)
         CallCFunctionFast(*z80_set_reg,#BC2,dhead\_BC2)
         CallCFunctionFast(*z80_set_reg,#DE2,dhead\_DE2)
         CallCFunctionFast(*z80_set_reg,#HL2,dhead\_HL2)
         CallCFunctionFast(*z80_set_reg,#IFF1,#True)
         CallCFunctionFast(*z80_set_reg,#IFF2,#True)
         CallCFunctionFast(*z80_set_reg,#IM,1)
         CallCFunctionFast(*z80_set_reg,#IRQV,255)
         CallCFunctionFast(*z80_set_reg,#IRQL,0)
         CallCFunctionFast(*z80_set_reg,#IR,(dhead\_I<<8)|dhead\_R)
         CallCFunctionFast(*z80_set_reg,#HALT,#False)
       ElseIf flen=8244 ;win
         ReadData(4,@whead.win,52)
         ReadData(4,*kb_io,8192)
         CallCFunctionFast(*z80_set_reg,#AF,whead\_AF)
         CallCFunctionFast(*z80_set_reg,#BC,whead\_BC)
         CallCFunctionFast(*z80_set_reg,#DE,whead\_DE)
         CallCFunctionFast(*z80_set_reg,#HL,whead\_HL)
         CallCFunctionFast(*z80_set_reg,#IX,whead\_IX)
         CallCFunctionFast(*z80_set_reg,#IY,whead\_IY)
         CallCFunctionFast(*z80_set_reg,#PC,whead\_PC)
         CallCFunctionFast(*z80_set_reg,#SP,whead\_SP)
         CallCFunctionFast(*z80_set_reg,#AF2,whead\_AF2)
         CallCFunctionFast(*z80_set_reg,#BC2,whead\_BC2)
         CallCFunctionFast(*z80_set_reg,#DE2,whead\_DE2)
         CallCFunctionFast(*z80_set_reg,#HL2,whead\_HL2)
         CallCFunctionFast(*z80_set_reg,#IFF1,#True)
         CallCFunctionFast(*z80_set_reg,#IFF2,#True)
         CallCFunctionFast(*z80_set_reg,#IM,1)
         CallCFunctionFast(*z80_set_reg,#IRQV,255)
         CallCFunctionFast(*z80_set_reg,#IRQL,0)
         CallCFunctionFast(*z80_set_reg,#IR,(dhead\_I<<8)|dhead\_R)
         CallCFunctionFast(*z80_set_reg,#HALT,#False)
       EndIf
       Case 2 ;grz raze native snapshot
         If *snap_adr
             ReadData(4,*snap_adr,68)
             ReadData(4,*kb_io,flen-Loc(4)) ; memconfig error !
            CallCFunctionFast(*z80_set_context,*snap_adr)
         Else
           MessageRequester("Error","Not enaugh memory!",0)
         EndIf
       EndSelect
       StatusBarText(0, 0, f$)
       CloseFile(4)
      EndIf
Return
Save:
    f$=SaveFileRequester("Save snapshot As...",f$,"Tape (*.gtp)|*.gtp|GAL Snapshot (*.gal)|*.gal|Raze snapshot (*.grz)|*.grz",ext)
       If *snap_adr And f$
      ext=SelectedFilePattern()
       Select ext
       Case 2 ; grz
         CallCFunctionFast(*z80_get_context,*snap_adr)
         If Right(f$,4)=".grz" : f$=Left(f$,Len(f$)-4) : EndIf
         If CreateFile(3,f$+".grz")
           WriteData(3,*snap_adr,68)
           WriteData(3,*kb_io,(fram+2)*1024)
           CloseFile(3)
           StatusBarText(0, 0, f$)
         Else
           MessageRequester("Error","File not saved!",0)
         EndIf
       Case 1 ; gal
         MessageRequester("Info","Format not supported !\nFile not saved!",0)
       Case 0 ; gtp
         tlen.q=FileSize(f$)
         If tlen=-1
           If Right(f$,4)<>".gtp" : f$+".gtp" : EndIf
         ElseIf tlen>-1 And OpenFile(3,f$)
           FileSeek(3,flen)
         Else
           MessageRequester("Info","File not saved!",0)
         EndIf
       EndSelect
      Else
        MessageRequester("Error","Not enaugh memory!",0)
      EndIf
Return
DataSection
gchset:
IncludeBinary "charset.bmp"
ROM_A:
IncludeBinary "ROM1.BIN"
ROM_B:
IncludeBinary "ROM2.BIN"
ROM_C:
IncludeBinary "ROM3.BIN"
CHRGEN:
IncludeBinary "CHRGEN.BIN"
MONITOR:
IncludeBinary "MONITOR.BIN"
KBMAP:
Data.i 0,#PB_Key_A,#PB_Key_B,#PB_Key_C,#PB_Key_D,#PB_Key_E,#PB_Key_F,#PB_Key_G,#PB_Key_H,#PB_Key_I,#PB_Key_J,#PB_Key_K,#PB_Key_L
Data.i #PB_Key_M,#PB_Key_N,#PB_Key_O,#PB_Key_P,#PB_Key_Q,#PB_Key_R,#PB_Key_S,#PB_Key_T,#PB_Key_U,#PB_Key_V,#PB_Key_W,#PB_Key_X
Data.i #PB_Key_Y,#PB_Key_Z,#PB_Key_Up,#PB_Key_Down,#PB_Key_Left,#PB_Key_Right,#PB_Key_Space,#PB_Key_0,#PB_Key_1,#PB_Key_2
Data.i #PB_Key_3,#PB_Key_4,#PB_Key_5,#PB_Key_6,#PB_Key_7,#PB_Key_8,#PB_Key_9,#PB_Key_SemiColon,#PB_Key_Minus,#PB_Key_Comma
Data.i #PB_Key_Equals,#PB_Key_Period,#PB_Key_Slash,#PB_Key_Return,#PB_Key_Escape,#PB_Key_RightControl,#PB_Key_Delete
Data.i#PB_Key_PageDown,#PB_Key_RightShift
WAV:
IncludeBinary "SINUS.WAV"
EndDataSection
; IDE Options = PureBasic 5.11 (Windows - x86)
; CursorPosition = 262
; FirstLine = 252
; Folding = -
; EnableThread
; EnableXP
; UseIcon = Galaxy2.ICO
; Executable = Galaksija.exe
; CPU = 1
; CompileSourceDirectory
