Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
9c5ed9ff0f | |||
cf598bda78 | |||
a9e606812a | |||
6ace9e95b3 |
62 changed files with 582 additions and 214 deletions
12
README.MD
12
README.MD
|
@ -18,16 +18,16 @@ fun to have an emulator 2000 lines of boring, by the book code. Would it? :-)
|
|||
|
||||
Additional Requirements
|
||||
------------------------------
|
||||
|
||||
|
||||
1. Pygame
|
||||
2. Numpy
|
||||
|
||||
|
||||
Instructions
|
||||
-------------
|
||||
|
||||
Run with python orao.py, enter BASIC using "BC". When asked about the memory
|
||||
size, press ENTER unless you don't want BASIC to use the entire available
|
||||
memory.
|
||||
memory.
|
||||
|
||||
WAV files containing programs / games should be located in the wav folder.
|
||||
|
||||
|
@ -37,7 +37,7 @@ will be created. Load it back using LOAD "filename".
|
|||
DMEM "filename", ADDR, LENGTH can also be used to save a fragment of memory,
|
||||
beginning at address ADDR and of length LENGTH (in decimal). LMEM "filename"
|
||||
loads it back.
|
||||
|
||||
|
||||
Clicking the POWER button does a warm reboot. You can then go back to BASIC
|
||||
with BW to keep the memory intact, or re-initialize with BC. The enclosed PDF
|
||||
describes the monitor mode and commands, but it is in Croatian only (Google
|
||||
|
@ -62,7 +62,5 @@ Then press F8 to load and start program.
|
|||
Known bugs
|
||||
----------
|
||||
|
||||
- Pygame and Pulseaudio crash occasionally. - it seems that this
|
||||
fork is less prone to lock-ups and **pygame*** crashes.
|
||||
Please report any issues you have.
|
||||
- Pygame and Pulseaudio crash occasionally. Please report any issues you have.
|
||||
- no error checking for input `.prg` file
|
||||
|
|
83
orao.py
83
orao.py
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf8 -*-
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame, numpy, sys, datetime
|
||||
from orao.cpu import CPU
|
||||
|
@ -27,7 +27,7 @@ pygame.init()
|
|||
pygame.time.set_timer(pygame.USEREVENT + 1, 40)
|
||||
|
||||
# create CPU
|
||||
cpu = CPU(bytearray([0xFF]*0xC000) + bytearray(open('ORAO13.ROM', 'rb').read()))
|
||||
cpu = CPU(bytearray([0xFF] * 0xC000) + bytearray(open("ORAO13.ROM", "rb").read()))
|
||||
cpu.channel = pygame.mixer.Channel(0)
|
||||
cpu.store_mem_listeners.append(video_mem_listener)
|
||||
cpu.store_mem_listeners.append(timer_mem_listener)
|
||||
|
@ -38,39 +38,46 @@ chargen_init(cpu.memory[0xE000:])
|
|||
view_cpu_state = CPUState()
|
||||
|
||||
# ram zero page & stack
|
||||
view_zp = MicroMemView(start_addr=0x0000, size=0x0200, caption='ZP & stack', disp_width=64)
|
||||
view_zp = MicroMemView(
|
||||
start_addr=0x0000, size=0x0200, caption="ZP & stack", disp_width=64
|
||||
)
|
||||
view_zp.listen(cpu)
|
||||
|
||||
# user ram view
|
||||
view_ram = MicroMemView(start_addr=0x0200, size=0x5E00, caption='RAM', disp_width=128)
|
||||
view_ram = MicroMemView(start_addr=0x0200, size=0x5E00, caption="RAM", disp_width=128)
|
||||
view_ram.listen(cpu)
|
||||
|
||||
# rom access view
|
||||
view_rom = MicroMemView(start_addr=0xC000, size=0x4000, caption='ROM', disp_width=256)
|
||||
view_rom = MicroMemView(start_addr=0xC000, size=0x4000, caption="ROM", disp_width=256)
|
||||
view_rom.listen(cpu)
|
||||
|
||||
view_screen = MicroMemView(start_addr=0x6000, size=0x2000, disp_width=32)
|
||||
view_screen.listen(cpu)
|
||||
|
||||
# status lines
|
||||
status_line = pygame.Surface((64 * 8, 4*8), depth=24)
|
||||
status_line = pygame.Surface((64 * 8, 4 * 8), depth=24)
|
||||
status_line.fill((0, 0, 0))
|
||||
chargen_draw_str(status_line, 0, 0, 'Orao Emulator v0.1')
|
||||
chargen_draw_str(status_line, 0, 0, "Orao Emulator v0.1")
|
||||
|
||||
# setup screen
|
||||
screen = pygame.display.set_mode((
|
||||
terminal.get_width() * 2 + 2 + int(max(view_rom.width, view_cpu_state.width * 2)),
|
||||
terminal.get_height() * 2 + 3*8 + 2 + 30
|
||||
))
|
||||
pygame.display.set_caption('Orao Emulator v0.1')
|
||||
screen = pygame.display.set_mode(
|
||||
(
|
||||
terminal.get_width() * 2
|
||||
+ 2
|
||||
+ int(max(view_rom.width, view_cpu_state.width * 2)),
|
||||
terminal.get_height() * 2 + 3 * 8 + 2 + 30,
|
||||
)
|
||||
)
|
||||
pygame.display.set_caption("Orao Emulator v0.1")
|
||||
|
||||
lc = (0xff, 0xcc, 0x00)
|
||||
chargen_draw_str(status_line, 0, 16, 'F12:', color=lc)
|
||||
chargen_draw_str(status_line, 24+8, 16, ' SCREENSHOT')
|
||||
lc = (0xFF, 0xCC, 0x00)
|
||||
chargen_draw_str(status_line, 0, 16, "F12:", color=lc)
|
||||
chargen_draw_str(status_line, 24 + 8, 16, " SCREENSHOT")
|
||||
|
||||
if MEM_LOAD_PRG is not None:
|
||||
chargen_draw_str(status_line, 0, 24, 'F8:', color=lc)
|
||||
chargen_draw_str(status_line, 24, 24, ' %s' % MEM_LOAD_PRG)
|
||||
chargen_draw_str(status_line, 0, 24, "F8:", color=lc)
|
||||
chargen_draw_str(status_line, 24, 24, " %s" % MEM_LOAD_PRG)
|
||||
|
||||
|
||||
def render_frame(frame_time_ms):
|
||||
view_cpu_state.render(cpu, frame_time_ms)
|
||||
|
@ -82,8 +89,8 @@ def render_frame(frame_time_ms):
|
|||
# blit
|
||||
screen.fill((0, 0, 0))
|
||||
screen.blit(pygame.transform.scale(terminal, (512, 512)), [0, 0])
|
||||
chargen_draw_str(status_line, 0, 8, 'Speed: {0:.2f} MHz'.format(ratio))
|
||||
screen.blit(status_line, [0, 512+1])
|
||||
chargen_draw_str(status_line, 0, 8, "Speed: {0:.2f} MHz".format(ratio))
|
||||
screen.blit(status_line, [0, 512 + 1])
|
||||
x = 512 + 1
|
||||
y = 0
|
||||
cx, y = view_cpu_state.blit(screen, [x, y], scale=2)
|
||||
|
@ -95,12 +102,13 @@ def render_frame(frame_time_ms):
|
|||
y2 += 5
|
||||
_, _ = view_rom.blit(screen, [x, y2], scale=1)
|
||||
|
||||
screen.blit(pygame.transform.scale(view_screen.read_map.surf, (512,512)), [0,0])
|
||||
screen.blit(pygame.transform.scale(view_screen.write_map.surf, (512,512)), [0,0])
|
||||
screen.blit(pygame.transform.scale(view_screen.read_map.surf, (512, 512)), [0, 0])
|
||||
screen.blit(pygame.transform.scale(view_screen.write_map.surf, (512, 512)), [0, 0])
|
||||
|
||||
# finish rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while running:
|
||||
|
@ -109,7 +117,7 @@ while running:
|
|||
for i in range(5000):
|
||||
cpu.step()
|
||||
|
||||
time_elapsed = (datetime.datetime.now()-before).microseconds + 1
|
||||
time_elapsed = (datetime.datetime.now() - before).microseconds + 1
|
||||
clock.tick()
|
||||
|
||||
for event in pygame.event.get():
|
||||
|
@ -118,8 +126,8 @@ while running:
|
|||
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
x, y = event.pos
|
||||
if 650 < x < 700 and 720 < y < 790: # Reset button
|
||||
cpu.__init__(cpu.memory[:]) # Warm reset
|
||||
if 650 < x < 700 and 720 < y < 790: # Reset button
|
||||
cpu.__init__(cpu.memory[:]) # Warm reset
|
||||
|
||||
orao_kbd_listener(event, cpu)
|
||||
|
||||
|
@ -131,13 +139,13 @@ while running:
|
|||
if pkeys[pygame.K_F8]:
|
||||
if MEM_LOAD_PRG is None:
|
||||
break
|
||||
print("LOADING: %s" % MEM_LOAD_PRG)
|
||||
print(("LOADING: %s" % MEM_LOAD_PRG))
|
||||
ba = bytearray(open(MEM_LOAD_PRG, "rb").read())
|
||||
|
||||
# read load address
|
||||
addr = ba[1] * 256 + ba[0]
|
||||
ba = ba[2:]
|
||||
print('Loadaddr: %04x' % addr)
|
||||
print(("Loadaddr: %04x" % addr))
|
||||
|
||||
# load file to memory
|
||||
for i in range(0, len(ba)):
|
||||
|
@ -150,22 +158,33 @@ while running:
|
|||
|
||||
if pkeys[pygame.K_F12]:
|
||||
now = datetime.datetime.now() # current date and time
|
||||
pygame.image.save(screen, "assets/screenshot-%s.png" % now.strftime("%Y%m%d-%H%M%S"))
|
||||
pygame.image.save(
|
||||
screen, "assets/screenshot-%s.png" % now.strftime("%Y%m%d-%H%M%S")
|
||||
)
|
||||
|
||||
if event.type == pygame.USEREVENT + 1:
|
||||
render_frame(clock.get_time())
|
||||
|
||||
cpu.tape_out = None if cpu.cycles - cpu.last_sound_cycles > 20000 else cpu.tape_out
|
||||
cpu.tape_out = (
|
||||
None if cpu.cycles - cpu.last_sound_cycles > 20000 else cpu.tape_out
|
||||
)
|
||||
|
||||
if len(cpu.sndbuf) > 4096 or cpu.sndbuf and cpu.cycles - cpu.last_sound_cycles > 20000:
|
||||
if (
|
||||
len(cpu.sndbuf) > 4096
|
||||
or cpu.sndbuf
|
||||
and cpu.cycles - cpu.last_sound_cycles > 20000
|
||||
):
|
||||
while cpu.channel.get_queue():
|
||||
if time_elapsed > 10000: break
|
||||
if time_elapsed > 10000:
|
||||
break
|
||||
|
||||
cpu.channel.queue(pygame.sndarray.make_sound(numpy.uint8(cpu.sndbuf)))
|
||||
cpu.sndbuf = []
|
||||
|
||||
overshoot = cpu.cycles - previous_loop_cycles - time_elapsed
|
||||
pygame.time.wait((overshoot > 0) * overshoot // 1000) # Pričekaj da budemo cycle exact
|
||||
pygame.time.wait(
|
||||
(overshoot > 0) * overshoot // 1000
|
||||
) # Pričekaj da budemo cycle exact
|
||||
|
||||
ratio = 1.0 * (cpu.cycles - previous_loop_cycles) / time_elapsed
|
||||
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
chars = None
|
||||
|
||||
def chargen_init(char_data):
|
||||
global chars
|
||||
chars = char_data
|
||||
|
||||
global chars
|
||||
chars = char_data
|
||||
|
||||
def chargen_draw_char(surf, px, py, ch, color=(0, 255, 0), bg=(0, 0, 0)):
|
||||
char_loc = (ord(ch) - 32) * 8
|
||||
for y in range(8):
|
||||
c = chars[char_loc + y]
|
||||
for x in range(8):
|
||||
if (c >> x) & 1:
|
||||
surf.set_at((px + x, py + y), color)
|
||||
else:
|
||||
surf.set_at((px + x, py + y), bg)
|
||||
char_loc = (ord(ch) - 32) * 8
|
||||
for y in range(8):
|
||||
c = chars[char_loc + y]
|
||||
for x in range(8):
|
||||
if (c >> x) & 1:
|
||||
surf.set_at((px + x, py + y), color)
|
||||
else:
|
||||
surf.set_at((px + x, py + y), bg)
|
||||
|
||||
|
||||
def chargen_draw_str(surf, px, py, str, color=(0, 255, 0), bg=(0, 0, 0)):
|
||||
for x in range(len(str)):
|
||||
chargen_draw_char(surf, px + x * 8, py, str[x], color=color, bg=bg)
|
||||
for x in range(len(str)):
|
||||
chargen_draw_char(surf, px + x * 8, py, str[x], color=color, bg=bg)
|
||||
|
|
509
orao/cpu.py
509
orao/cpu.py
|
@ -1,61 +1,196 @@
|
|||
# -*- coding: utf8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import wave
|
||||
|
||||
class CPU(object):
|
||||
CARRY, ZERO, INTERRUPT, DECIMAL, BREAK, UNUSED, OVERFLOW, NEGATIVE = [2**i for i in range(8)]
|
||||
CARRY, ZERO, INTERRUPT, DECIMAL, BREAK, UNUSED, OVERFLOW, NEGATIVE = [
|
||||
2**i for i in range(8)
|
||||
]
|
||||
alphaarray = None
|
||||
store_mem_listeners = []
|
||||
read_mem_listeners = []
|
||||
|
||||
def __init__(self, memory):
|
||||
s, self.tape_out, self.filename, self.samples = self, None, None, 0
|
||||
s.memory, s.tape, s.flipflop, s.last_sound_cycles, s.sndbuf = memory, None, 0, -20000, []
|
||||
s.memory, s.tape, s.flipflop, s.last_sound_cycles, s.sndbuf = (
|
||||
memory,
|
||||
None,
|
||||
0,
|
||||
-20000,
|
||||
[],
|
||||
)
|
||||
s.cycles, s.pc, s.flags, s.sp, s.a, s.x, s.y = 0, 0xFF89, 48, 0xFF, 0, 0, 0
|
||||
s.executed = []
|
||||
|
||||
s._opcodes = { 0x00:(s.BRK,s.no,7), 0x01:(s.ORA,s.ix,6), 0x05:(s.ORA,s.zp,3),
|
||||
0x06:(s.ASL,s.zp,5), 0x08:(s.PHP,s.no,3), 0x09:(s.ORA,s.im,2), 0x0a:(s.ASL,s.no,2),
|
||||
0x0d:(s.ORA,s.ab,4), 0x0e:(s.ASL,s.ab,6), 0x10:(s.BPL,s.re,2), 0x11:(s.ORA,s.iy,6),
|
||||
0x15:(s.ORA,s.zx,4), 0x16:(s.ASL,s.zx,6), 0x18:(s.CLC,s.no,2), 0x19:(s.ORA,s.ay,5),
|
||||
0x1d:(s.ORA,s.ax,5), 0x1e:(s.ASL,s.ax,7), 0x20:(s.JSR,s.jm,6), 0x21:(s.AND,s.ix,6),
|
||||
0x24:(s.BIT,s.zp,3), 0x25:(s.AND,s.zp,3), 0x26:(s.ROL,s.zp,5), 0x28:(s.PLP,s.no,4),
|
||||
0x29:(s.AND,s.im,2), 0x2a:(s.ROL,s.no,2), 0x2c:(s.BIT,s.ab,4), 0x2d:(s.AND,s.ab,4),
|
||||
0x2e:(s.ROL,s.ab,6), 0x30:(s.BMI,s.re,2), 0x31:(s.AND,s.iy,6), 0x35:(s.AND,s.zx,4),
|
||||
0x36:(s.ROL,s.zx,6), 0x38:(s.SEC,s.no,2), 0x39:(s.AND,s.ay,5), 0x3d:(s.AND,s.ax,5),
|
||||
0x3e:(s.ROL,s.ax,7), 0x40:(s.RTI,s.no,6), 0x41:(s.EOR,s.ix,6), 0x45:(s.EOR,s.zp,3),
|
||||
0x46:(s.LSR,s.zp,5), 0x48:(s.PHA,s.no,3), 0x49:(s.EOR,s.im,2), 0x4a:(s.LSR,s.no,2),
|
||||
0x4c:(s.JMP,s.jm,3), 0x4d:(s.EOR,s.ab,4), 0x4e:(s.LSR,s.ab,6), 0x50:(s.BVC,s.re,2),
|
||||
0x51:(s.EOR,s.iy,6), 0x55:(s.EOR,s.zx,4), 0x56:(s.LSR,s.zx,6), 0x58:(s.CLI,s.no,2),
|
||||
0x59:(s.EOR,s.ay,5), 0x5d:(s.EOR,s.ax,5), 0x5e:(s.LSR,s.ax,7), 0x60:(s.RTS,s.no,6),
|
||||
0x61:(s.ADC,s.ix,6), 0x65:(s.ADC,s.zp,3), 0x66:(s.ROR,s.zp,5), 0x68:(s.PLA,s.no,4),
|
||||
0x69:(s.ADC,s.im,2), 0x6a:(s.ROR,s.no,2), 0x6c:(s.JMP,s.id,5), 0x6d:(s.ADC,s.ab,4),
|
||||
0x6e:(s.ROR,s.ab,6), 0x70:(s.BVS,s.re,2), 0x71:(s.ADC,s.iy,6), 0x75:(s.ADC,s.zx,4),
|
||||
0x76:(s.ROR,s.zx,6), 0x78:(s.SEI,s.no,2), 0x79:(s.ADC,s.ay,5), 0x7d:(s.ADC,s.ax,5),
|
||||
0x7e:(s.ROR,s.ax,7), 0x81:(s.STA,s.ix,6), 0x84:(s.STY,s.zp,3), 0x85:(s.STA,s.zp,3),
|
||||
0x86:(s.STX,s.zp,3), 0x88:(s.DEY,s.no,2), 0x8a:(s.TXA,s.no,2), 0x8c:(s.STY,s.ab,4),
|
||||
0x8d:(s.STA,s.ab,4), 0x8e:(s.STX,s.ab,4), 0x90:(s.BCC,s.re,2), 0x91:(s.STA,s.iy,6),
|
||||
0x94:(s.STY,s.zx,4), 0x95:(s.STA,s.zx,4), 0x96:(s.STX,s.zy,4), 0x98:(s.TYA,s.no,2),
|
||||
0x99:(s.STA,s.ay,5), 0x9a:(s.TXS,s.no,2), 0x9d:(s.STA,s.ax,5), 0xa0:(s.LDY,s.im,2),
|
||||
0xa1:(s.LDA,s.ix,6), 0xa2:(s.LDX,s.im,2), 0xa4:(s.LDY,s.zp,3), 0xa5:(s.LDA,s.zp,3),
|
||||
0xa6:(s.LDX,s.zp,3), 0xa8:(s.TAY,s.no,2), 0xa9:(s.LDA,s.im,2), 0xaa:(s.TAX,s.no,2),
|
||||
0xac:(s.LDY,s.ab,4), 0xad:(s.LDA,s.ab,4), 0xae:(s.LDX,s.ab,4), 0xb0:(s.BCS,s.re,2),
|
||||
0xb1:(s.LDA,s.iy,6), 0xb4:(s.LDY,s.zx,4), 0xb5:(s.LDA,s.zx,4), 0xb6:(s.LDX,s.zy,4),
|
||||
0xb8:(s.CLV,s.no,2), 0xb9:(s.LDA,s.ay,4), 0xba:(s.TSX,s.no,2), 0xbc:(s.LDY,s.ax,4),
|
||||
0xbd:(s.LDA,s.ax,4), 0xbe:(s.LDX,s.ay,4), 0xc0:(s.CPY,s.im,2), 0xc1:(s.CMP,s.ix,6),
|
||||
0xc4:(s.CPY,s.zp,3), 0xc5:(s.CMP,s.zp,3), 0xc6:(s.DEC,s.zp,5), 0xc8:(s.INY,s.no,2),
|
||||
0xc9:(s.CMP,s.im,2), 0xca:(s.DEX,s.no,2), 0xcc:(s.CPY,s.ab,4), 0xcd:(s.CMP,s.ab,4),
|
||||
0xce:(s.DEC,s.ab,6), 0xd0:(s.BNE,s.re,2), 0xd1:(s.CMP,s.iy,6), 0xd5:(s.CMP,s.zx,4),
|
||||
0xd6:(s.DEC,s.zx,6), 0xd8:(s.CLD,s.no,2), 0xd9:(s.CMP,s.ay,5), 0xdd:(s.CMP,s.ax,5),
|
||||
0xde:(s.DEC,s.ax,7), 0xe0:(s.CPX,s.im,2), 0xe1:(s.SBC,s.ix,6), 0xe4:(s.CPX,s.zp,3),
|
||||
0xe5:(s.SBC,s.zp,3), 0xe6:(s.INC,s.zp,5), 0xe8:(s.INX,s.no,2), 0xe9:(s.SBC,s.im,2),
|
||||
0xea:(s.NOP,s.no,2), 0xec:(s.CPX,s.ab,4), 0xed:(s.SBC,s.ab,4), 0xee:(s.INC,s.ab,6),
|
||||
0xf0:(s.BEQ,s.re,2), 0xf1:(s.SBC,s.iy,6), 0xf5:(s.SBC,s.zx,4), 0xf6:(s.INC,s.zx,6),
|
||||
0xf8:(s.SED,s.no,2), 0xf9:(s.SBC,s.ay,5), 0xfd:(s.SBC,s.ax,5), 0xfe:(s.INC,s.ax,7)}
|
||||
s._opcodes = {
|
||||
0x00: (s.BRK, s.no, 7),
|
||||
0x01: (s.ORA, s.ix, 6),
|
||||
0x05: (s.ORA, s.zp, 3),
|
||||
0x06: (s.ASL, s.zp, 5),
|
||||
0x08: (s.PHP, s.no, 3),
|
||||
0x09: (s.ORA, s.im, 2),
|
||||
0x0A: (s.ASL, s.no, 2),
|
||||
0x0D: (s.ORA, s.ab, 4),
|
||||
0x0E: (s.ASL, s.ab, 6),
|
||||
0x10: (s.BPL, s.re, 2),
|
||||
0x11: (s.ORA, s.iy, 6),
|
||||
0x15: (s.ORA, s.zx, 4),
|
||||
0x16: (s.ASL, s.zx, 6),
|
||||
0x18: (s.CLC, s.no, 2),
|
||||
0x19: (s.ORA, s.ay, 5),
|
||||
0x1D: (s.ORA, s.ax, 5),
|
||||
0x1E: (s.ASL, s.ax, 7),
|
||||
0x20: (s.JSR, s.jm, 6),
|
||||
0x21: (s.AND, s.ix, 6),
|
||||
0x24: (s.BIT, s.zp, 3),
|
||||
0x25: (s.AND, s.zp, 3),
|
||||
0x26: (s.ROL, s.zp, 5),
|
||||
0x28: (s.PLP, s.no, 4),
|
||||
0x29: (s.AND, s.im, 2),
|
||||
0x2A: (s.ROL, s.no, 2),
|
||||
0x2C: (s.BIT, s.ab, 4),
|
||||
0x2D: (s.AND, s.ab, 4),
|
||||
0x2E: (s.ROL, s.ab, 6),
|
||||
0x30: (s.BMI, s.re, 2),
|
||||
0x31: (s.AND, s.iy, 6),
|
||||
0x35: (s.AND, s.zx, 4),
|
||||
0x36: (s.ROL, s.zx, 6),
|
||||
0x38: (s.SEC, s.no, 2),
|
||||
0x39: (s.AND, s.ay, 5),
|
||||
0x3D: (s.AND, s.ax, 5),
|
||||
0x3E: (s.ROL, s.ax, 7),
|
||||
0x40: (s.RTI, s.no, 6),
|
||||
0x41: (s.EOR, s.ix, 6),
|
||||
0x45: (s.EOR, s.zp, 3),
|
||||
0x46: (s.LSR, s.zp, 5),
|
||||
0x48: (s.PHA, s.no, 3),
|
||||
0x49: (s.EOR, s.im, 2),
|
||||
0x4A: (s.LSR, s.no, 2),
|
||||
0x4C: (s.JMP, s.jm, 3),
|
||||
0x4D: (s.EOR, s.ab, 4),
|
||||
0x4E: (s.LSR, s.ab, 6),
|
||||
0x50: (s.BVC, s.re, 2),
|
||||
0x51: (s.EOR, s.iy, 6),
|
||||
0x55: (s.EOR, s.zx, 4),
|
||||
0x56: (s.LSR, s.zx, 6),
|
||||
0x58: (s.CLI, s.no, 2),
|
||||
0x59: (s.EOR, s.ay, 5),
|
||||
0x5D: (s.EOR, s.ax, 5),
|
||||
0x5E: (s.LSR, s.ax, 7),
|
||||
0x60: (s.RTS, s.no, 6),
|
||||
0x61: (s.ADC, s.ix, 6),
|
||||
0x65: (s.ADC, s.zp, 3),
|
||||
0x66: (s.ROR, s.zp, 5),
|
||||
0x68: (s.PLA, s.no, 4),
|
||||
0x69: (s.ADC, s.im, 2),
|
||||
0x6A: (s.ROR, s.no, 2),
|
||||
0x6C: (s.JMP, s.id, 5),
|
||||
0x6D: (s.ADC, s.ab, 4),
|
||||
0x6E: (s.ROR, s.ab, 6),
|
||||
0x70: (s.BVS, s.re, 2),
|
||||
0x71: (s.ADC, s.iy, 6),
|
||||
0x75: (s.ADC, s.zx, 4),
|
||||
0x76: (s.ROR, s.zx, 6),
|
||||
0x78: (s.SEI, s.no, 2),
|
||||
0x79: (s.ADC, s.ay, 5),
|
||||
0x7D: (s.ADC, s.ax, 5),
|
||||
0x7E: (s.ROR, s.ax, 7),
|
||||
0x81: (s.STA, s.ix, 6),
|
||||
0x84: (s.STY, s.zp, 3),
|
||||
0x85: (s.STA, s.zp, 3),
|
||||
0x86: (s.STX, s.zp, 3),
|
||||
0x88: (s.DEY, s.no, 2),
|
||||
0x8A: (s.TXA, s.no, 2),
|
||||
0x8C: (s.STY, s.ab, 4),
|
||||
0x8D: (s.STA, s.ab, 4),
|
||||
0x8E: (s.STX, s.ab, 4),
|
||||
0x90: (s.BCC, s.re, 2),
|
||||
0x91: (s.STA, s.iy, 6),
|
||||
0x94: (s.STY, s.zx, 4),
|
||||
0x95: (s.STA, s.zx, 4),
|
||||
0x96: (s.STX, s.zy, 4),
|
||||
0x98: (s.TYA, s.no, 2),
|
||||
0x99: (s.STA, s.ay, 5),
|
||||
0x9A: (s.TXS, s.no, 2),
|
||||
0x9D: (s.STA, s.ax, 5),
|
||||
0xA0: (s.LDY, s.im, 2),
|
||||
0xA1: (s.LDA, s.ix, 6),
|
||||
0xA2: (s.LDX, s.im, 2),
|
||||
0xA4: (s.LDY, s.zp, 3),
|
||||
0xA5: (s.LDA, s.zp, 3),
|
||||
0xA6: (s.LDX, s.zp, 3),
|
||||
0xA8: (s.TAY, s.no, 2),
|
||||
0xA9: (s.LDA, s.im, 2),
|
||||
0xAA: (s.TAX, s.no, 2),
|
||||
0xAC: (s.LDY, s.ab, 4),
|
||||
0xAD: (s.LDA, s.ab, 4),
|
||||
0xAE: (s.LDX, s.ab, 4),
|
||||
0xB0: (s.BCS, s.re, 2),
|
||||
0xB1: (s.LDA, s.iy, 6),
|
||||
0xB4: (s.LDY, s.zx, 4),
|
||||
0xB5: (s.LDA, s.zx, 4),
|
||||
0xB6: (s.LDX, s.zy, 4),
|
||||
0xB8: (s.CLV, s.no, 2),
|
||||
0xB9: (s.LDA, s.ay, 4),
|
||||
0xBA: (s.TSX, s.no, 2),
|
||||
0xBC: (s.LDY, s.ax, 4),
|
||||
0xBD: (s.LDA, s.ax, 4),
|
||||
0xBE: (s.LDX, s.ay, 4),
|
||||
0xC0: (s.CPY, s.im, 2),
|
||||
0xC1: (s.CMP, s.ix, 6),
|
||||
0xC4: (s.CPY, s.zp, 3),
|
||||
0xC5: (s.CMP, s.zp, 3),
|
||||
0xC6: (s.DEC, s.zp, 5),
|
||||
0xC8: (s.INY, s.no, 2),
|
||||
0xC9: (s.CMP, s.im, 2),
|
||||
0xCA: (s.DEX, s.no, 2),
|
||||
0xCC: (s.CPY, s.ab, 4),
|
||||
0xCD: (s.CMP, s.ab, 4),
|
||||
0xCE: (s.DEC, s.ab, 6),
|
||||
0xD0: (s.BNE, s.re, 2),
|
||||
0xD1: (s.CMP, s.iy, 6),
|
||||
0xD5: (s.CMP, s.zx, 4),
|
||||
0xD6: (s.DEC, s.zx, 6),
|
||||
0xD8: (s.CLD, s.no, 2),
|
||||
0xD9: (s.CMP, s.ay, 5),
|
||||
0xDD: (s.CMP, s.ax, 5),
|
||||
0xDE: (s.DEC, s.ax, 7),
|
||||
0xE0: (s.CPX, s.im, 2),
|
||||
0xE1: (s.SBC, s.ix, 6),
|
||||
0xE4: (s.CPX, s.zp, 3),
|
||||
0xE5: (s.SBC, s.zp, 3),
|
||||
0xE6: (s.INC, s.zp, 5),
|
||||
0xE8: (s.INX, s.no, 2),
|
||||
0xE9: (s.SBC, s.im, 2),
|
||||
0xEA: (s.NOP, s.no, 2),
|
||||
0xEC: (s.CPX, s.ab, 4),
|
||||
0xED: (s.SBC, s.ab, 4),
|
||||
0xEE: (s.INC, s.ab, 6),
|
||||
0xF0: (s.BEQ, s.re, 2),
|
||||
0xF1: (s.SBC, s.iy, 6),
|
||||
0xF5: (s.SBC, s.zx, 4),
|
||||
0xF6: (s.INC, s.zx, 6),
|
||||
0xF8: (s.SED, s.no, 2),
|
||||
0xF9: (s.SBC, s.ay, 5),
|
||||
0xFD: (s.SBC, s.ax, 5),
|
||||
0xFE: (s.INC, s.ax, 7),
|
||||
}
|
||||
|
||||
|
||||
s.ticks = {s.im: 1, s.zp: 1, s.zx: 1, s.zy: 1, s.ab: 2, s.ax: 2, s.no: 0,
|
||||
s.ay: 2, s.jm: 2, s.id: 2, s.ix: 1, s.iy: 1, s.re: 1}
|
||||
s.ticks = {
|
||||
s.im: 1,
|
||||
s.zp: 1,
|
||||
s.zx: 1,
|
||||
s.zy: 1,
|
||||
s.ab: 2,
|
||||
s.ax: 2,
|
||||
s.no: 0,
|
||||
s.ay: 2,
|
||||
s.jm: 2,
|
||||
s.id: 2,
|
||||
s.ix: 1,
|
||||
s.iy: 1,
|
||||
s.re: 1,
|
||||
}
|
||||
|
||||
s.addr_fmt = {
|
||||
s.im: lambda addr: "#$%02X" % s.memory[addr],
|
||||
|
@ -73,7 +208,8 @@ class CPU(object):
|
|||
s.re: lambda addr: "$%04X" % (addr + self.byte2signed(s.memory[addr]) + 1),
|
||||
}
|
||||
|
||||
def get_flag(self, flag): return self.flags & flag != 0
|
||||
def get_flag(self, flag):
|
||||
return self.flags & flag != 0
|
||||
|
||||
def set_flag(self, flag, boolean):
|
||||
self.flags = self.flags | flag if boolean else self.flags & ~(flag)
|
||||
|
@ -83,15 +219,17 @@ class CPU(object):
|
|||
self.set_flag(self.NEGATIVE, src & 0x80)
|
||||
return src
|
||||
|
||||
def get_word(self, addr): return 256 * self.get_byte(addr + 1) + self.get_byte(addr)
|
||||
def get_word(self, addr):
|
||||
return 256 * self.get_byte(addr + 1) + self.get_byte(addr)
|
||||
|
||||
def get_filename(self): return 'wav/{0}.WAV'.format(str(self.memory[592:602], 'ASCII').rstrip())
|
||||
def get_filename(self):
|
||||
return 'wav/{0}.WAV'.format(str(self.memory[592:602], 'ASCII').rstrip())
|
||||
|
||||
def speaker(self):
|
||||
self.flipflop ^= 1
|
||||
|
||||
self.samples = int((self.cycles - self.last_sound_cycles) / 22.675)
|
||||
if 1 < self.samples < 1000: # Ogranici frekventno podrucje
|
||||
if 1 < self.samples < 1000: # Ogranici frekventno podrucje
|
||||
self.sndbuf += [255] * self.samples + [0] * self.samples
|
||||
self.last_sound_cycles = self.cycles
|
||||
|
||||
|
@ -101,10 +239,9 @@ class CPU(object):
|
|||
yield 255 * (j > 128)
|
||||
|
||||
def get_byte(self, addr):
|
||||
if addr == 0x87FF: # Adresa ulaza kasetofona
|
||||
if addr == 0x87FF: # Adresa ulaza kasetofona
|
||||
if not self.tape:
|
||||
self.tape = self.tape_load_gen()
|
||||
|
||||
self.tape = self.tape_load_gen()
|
||||
try:
|
||||
return next(self.tape)
|
||||
|
||||
|
@ -112,7 +249,8 @@ class CPU(object):
|
|||
self.tape = None
|
||||
return 0x00
|
||||
|
||||
if addr == 0x8800: self.speaker() # Zvucnik
|
||||
if addr == 0x8800:
|
||||
self.speaker() # Zvucnik
|
||||
|
||||
if addr is not None:
|
||||
for listener in self.read_mem_listeners:
|
||||
|
@ -121,11 +259,12 @@ class CPU(object):
|
|||
return self.memory[addr] if addr is not None else self.a
|
||||
|
||||
def store_byte(self, addr, val):
|
||||
if addr is None: # Akumulator
|
||||
if addr is None: # Akumulator
|
||||
self.a = val & 0xFF
|
||||
return
|
||||
|
||||
if addr == 0x8800: self.speaker() # Zvucnik
|
||||
if addr == 0x8800:
|
||||
self.speaker() # Zvucnik
|
||||
|
||||
self.memory[addr] = val & 0xFF
|
||||
|
||||
|
@ -141,24 +280,48 @@ class CPU(object):
|
|||
return self.get_byte(256 + self.sp)
|
||||
|
||||
def stack_push_word(self, val):
|
||||
self.stack_push((val >> 8) & 0xFF)
|
||||
self.stack_push(val & 0xFF)
|
||||
list(map(self.stack_push, [(val >> 8) & 0xFF, val & 0xFF]))
|
||||
|
||||
def stack_pop_word(self):
|
||||
return self.stack_pop() + (self.stack_pop() << 8)
|
||||
|
||||
def stack_pop_word(self): return self.stack_pop() + (self.stack_pop() << 8)
|
||||
###########################################################################
|
||||
# Adresni nacini
|
||||
def im(self): return self.pc
|
||||
def zp(self): return self.get_byte(self.pc)
|
||||
def zx(self): return (self.zp() + self.x) & 0xFF
|
||||
def zy(self): return (self.zp() + self.y) & 0xFF
|
||||
def ab(self): return self.get_word(self.pc)
|
||||
def ax(self): return self._ab(self.x)
|
||||
def ay(self): return self._ab(self.y)
|
||||
def ix(self): return self.get_word((self.zp() + self.x) & 0xFF)
|
||||
def iy(self): return (self.get_word(self.zp()) + self.y) & 0xFFFF
|
||||
def id(self): return self.get_word(self.ab())
|
||||
def jm(self): return self.ab()
|
||||
def no(self): return None
|
||||
def im(self):
|
||||
return self.pc
|
||||
|
||||
def zp(self):
|
||||
return self.get_byte(self.pc)
|
||||
|
||||
def zx(self):
|
||||
return (self.zp() + self.x) & 0xFF
|
||||
|
||||
def zy(self):
|
||||
return (self.zp() + self.y) & 0xFF
|
||||
|
||||
def ab(self):
|
||||
return self.get_word(self.pc)
|
||||
|
||||
def ax(self):
|
||||
return self._ab(self.x)
|
||||
|
||||
def ay(self):
|
||||
return self._ab(self.y)
|
||||
|
||||
def ix(self):
|
||||
return self.get_word((self.zp() + self.x) & 0xFF)
|
||||
|
||||
def iy(self):
|
||||
return (self.get_word(self.zp()) + self.y) & 0xFFFF
|
||||
|
||||
def id(self):
|
||||
return self.get_word(self.ab())
|
||||
|
||||
def jm(self):
|
||||
return self.ab()
|
||||
|
||||
def no(self):
|
||||
return None
|
||||
|
||||
def _ab(self, diff):
|
||||
a1 = self.ab()
|
||||
|
@ -177,39 +340,89 @@ class CPU(object):
|
|||
|
||||
###########################################################################
|
||||
# Instrukcije
|
||||
def TAX(self, d): self.x = self.set_nz(self.a)
|
||||
def TXA(self, d): self.a = self.set_nz(self.x)
|
||||
def TAY(self, d): self.y = self.set_nz(self.a)
|
||||
def TYA(self, d): self.a = self.set_nz(self.y)
|
||||
def TSX(self, d): self.x = self.set_nz(self.sp)
|
||||
def TXS(self, d): self.sp = self.x
|
||||
def TAX(self, d):
|
||||
self.x = self.set_nz(self.a)
|
||||
|
||||
def LDA(self, addr): self.a = self.set_nz(self.get_byte(addr))
|
||||
def LDX(self, addr): self.x = self.set_nz(self.get_byte(addr))
|
||||
def LDY(self, addr): self.y = self.set_nz(self.get_byte(addr))
|
||||
def STA(self, addr): self.store_byte(addr, self.a)
|
||||
def STX(self, addr): self.store_byte(addr, self.x)
|
||||
def STY(self, addr): self.store_byte(addr, self.y)
|
||||
def TXA(self, d):
|
||||
self.a = self.set_nz(self.x)
|
||||
|
||||
def AND(self, addr): self.a = self.set_nz(self.get_byte(addr) & self.a)
|
||||
def ORA(self, addr): self.a = self.set_nz(self.get_byte(addr) | self.a)
|
||||
def EOR(self, addr): self.a = self.set_nz(self.get_byte(addr) ^ self.a)
|
||||
def TAY(self, d):
|
||||
self.y = self.set_nz(self.a)
|
||||
|
||||
def CLC(self, d): self.set_flag(self.CARRY, False)
|
||||
def SEC(self, d): self.set_flag(self.CARRY, True)
|
||||
def CLD(self, d): self.set_flag(self.DECIMAL, False)
|
||||
def SED(self, d): self.set_flag(self.DECIMAL, True)
|
||||
def CLI(self, d): self.set_flag(self.INTERRUPT, False)
|
||||
def SEI(self, d): self.set_flag(self.INTERRUPT, True)
|
||||
def CLV(self, d): self.set_flag(self.OVERFLOW, False)
|
||||
def TYA(self, d):
|
||||
self.a = self.set_nz(self.y)
|
||||
|
||||
def INX(self, d): self.x = self.set_nz((self.x + 1) & 0xFF)
|
||||
def INY(self, d): self.y = self.set_nz((self.y + 1) & 0xFF)
|
||||
def DEX(self, d): self.x = self.set_nz((self.x - 1) & 0xFF)
|
||||
def DEY(self, d): self.y = self.set_nz((self.y - 1) & 0xFF)
|
||||
def TSX(self, d):
|
||||
self.x = self.set_nz(self.sp)
|
||||
|
||||
def INC(self, addr): self.store_byte(addr, self.set_nz(self.get_byte(addr) + 1))
|
||||
def DEC(self, addr): self.store_byte(addr, self.set_nz(self.get_byte(addr) - 1))
|
||||
def TXS(self, d):
|
||||
self.sp = self.x
|
||||
|
||||
def LDA(self, addr):
|
||||
self.a = self.set_nz(self.get_byte(addr))
|
||||
|
||||
def LDX(self, addr):
|
||||
self.x = self.set_nz(self.get_byte(addr))
|
||||
|
||||
def LDY(self, addr):
|
||||
self.y = self.set_nz(self.get_byte(addr))
|
||||
|
||||
def STA(self, addr):
|
||||
self.store_byte(addr, self.a)
|
||||
|
||||
def STX(self, addr):
|
||||
self.store_byte(addr, self.x)
|
||||
|
||||
def STY(self, addr):
|
||||
self.store_byte(addr, self.y)
|
||||
|
||||
def AND(self, addr):
|
||||
self.a = self.set_nz(self.get_byte(addr) & self.a)
|
||||
|
||||
def ORA(self, addr):
|
||||
self.a = self.set_nz(self.get_byte(addr) | self.a)
|
||||
|
||||
def EOR(self, addr):
|
||||
self.a = self.set_nz(self.get_byte(addr) ^ self.a)
|
||||
|
||||
def CLC(self, d):
|
||||
self.set_flag(self.CARRY, False)
|
||||
|
||||
def SEC(self, d):
|
||||
self.set_flag(self.CARRY, True)
|
||||
|
||||
def CLD(self, d):
|
||||
self.set_flag(self.DECIMAL, False)
|
||||
|
||||
def SED(self, d):
|
||||
self.set_flag(self.DECIMAL, True)
|
||||
|
||||
def CLI(self, d):
|
||||
self.set_flag(self.INTERRUPT, False)
|
||||
|
||||
def SEI(self, d):
|
||||
self.set_flag(self.INTERRUPT, True)
|
||||
|
||||
def CLV(self, d):
|
||||
self.set_flag(self.OVERFLOW, False)
|
||||
|
||||
def INX(self, d):
|
||||
self.x = self.set_nz((self.x + 1) & 0xFF)
|
||||
|
||||
def INY(self, d):
|
||||
self.y = self.set_nz((self.y + 1) & 0xFF)
|
||||
|
||||
def DEX(self, d):
|
||||
self.x = self.set_nz((self.x - 1) & 0xFF)
|
||||
|
||||
def DEY(self, d):
|
||||
self.y = self.set_nz((self.y - 1) & 0xFF)
|
||||
|
||||
def INC(self, addr):
|
||||
self.store_byte(addr, self.set_nz(self.get_byte(addr) + 1))
|
||||
|
||||
def DEC(self, addr):
|
||||
self.store_byte(addr, self.set_nz(self.get_byte(addr) - 1))
|
||||
|
||||
def ASL(self, addr):
|
||||
operand = self.get_byte(addr)
|
||||
|
@ -223,11 +436,20 @@ class CPU(object):
|
|||
self.set_flag(self.NEGATIVE, op & self.NEGATIVE)
|
||||
self.set_flag(self.OVERFLOW, op & self.OVERFLOW)
|
||||
|
||||
def PHP(self, d): self.stack_push(self.flags | self.BREAK | self.UNUSED)
|
||||
def PHA(self, d): self.stack_push(self.a)
|
||||
def PLP(self, d): self.flags = self.stack_pop()
|
||||
def PLA(self, d): self.a = self.set_nz(self.stack_pop())
|
||||
def NOP(self, d): pass
|
||||
def PHP(self, d):
|
||||
self.stack_push(self.flags | self.BREAK | self.UNUSED)
|
||||
|
||||
def PHA(self, d):
|
||||
self.stack_push(self.a)
|
||||
|
||||
def PLP(self, d):
|
||||
self.flags = self.stack_pop()
|
||||
|
||||
def PLA(self, d):
|
||||
self.a = self.set_nz(self.stack_pop())
|
||||
|
||||
def NOP(self, d):
|
||||
pass
|
||||
|
||||
def ROR(self, addr):
|
||||
value = self.get_byte(addr) >> 1 | self.get_flag(self.CARRY) * 128
|
||||
|
@ -246,14 +468,17 @@ class CPU(object):
|
|||
self.SEI(0)
|
||||
self.pc = self.get_word(0xFFFE) # IRQ
|
||||
|
||||
def JMP(self, addr): self.pc = addr - 2
|
||||
def JMP(self, addr):
|
||||
self.pc = addr - 2
|
||||
|
||||
def JSR(self, addr):
|
||||
if addr == 0xE7B7 and self.pc > 0xC000: # samo i jedino ako rutinu poziva ROM
|
||||
if addr == 0xE7B7 and self.pc > 0xC000: # samo i jedino ako rutinu poziva ROM
|
||||
if not self.tape_out:
|
||||
self.tape_out = wave.open(self.get_filename(), 'w')
|
||||
self.tape_out.setparams((1, 1, 44100, 0, 'NONE', 'not compressed'))
|
||||
self.tape_out.writeframes(chr(255 * self.flipflop) * (1 + (self.y > 15)) * 10)
|
||||
self.tape_out = wave.open(self.get_filename(), "w")
|
||||
self.tape_out.setparams((1, 1, 44100, 0, "NONE", "not compressed"))
|
||||
self.tape_out.writeframes(
|
||||
chr(255 * self.flipflop) * (1 + (self.y > 15)) * 10
|
||||
)
|
||||
|
||||
self.stack_push_word((self.pc + 1) & 0xFFFF)
|
||||
self.pc = addr - 2
|
||||
|
@ -273,49 +498,80 @@ class CPU(object):
|
|||
self.pc = (self.pc + 1) & 0xFFFF
|
||||
|
||||
def ADDITION(self, arg):
|
||||
result = (arg & 0XFF) + self.a + self.get_flag(self.CARRY)
|
||||
result = (arg & 0xFF) + self.a + self.get_flag(self.CARRY)
|
||||
self.set_flag(self.OVERFLOW, (~(arg ^ self.a)) & (self.a ^ result) & 0x80)
|
||||
self.set_flag(self.CARRY, result > 255)
|
||||
self.a = self.set_nz(result) & 0xFF
|
||||
|
||||
def ADC(self, addr): self.ADDITION(self.get_byte(addr))
|
||||
def SBC(self, addr): self.ADDITION(~self.get_byte(addr))
|
||||
def ADC(self, addr):
|
||||
self.ADDITION(self.get_byte(addr))
|
||||
|
||||
def SBC(self, addr):
|
||||
self.ADDITION(~self.get_byte(addr))
|
||||
|
||||
def COMPARE(self, what, addr):
|
||||
self.set_flag(self.CARRY, self.set_nz(what - self.get_byte(addr)) >= 0)
|
||||
|
||||
def CMP(self, addr): self.COMPARE(self.a, addr)
|
||||
def CPX(self, addr): self.COMPARE(self.x, addr)
|
||||
def CPY(self, addr): self.COMPARE(self.y, addr)
|
||||
def CMP(self, addr):
|
||||
self.COMPARE(self.a, addr)
|
||||
|
||||
def CPX(self, addr):
|
||||
self.COMPARE(self.x, addr)
|
||||
|
||||
def CPY(self, addr):
|
||||
self.COMPARE(self.y, addr)
|
||||
|
||||
def BRANCH(self, addr, flag, condition):
|
||||
if self.get_flag(flag) is condition:
|
||||
self.pc = addr
|
||||
self.cycles += 1 # Ako se grana, to je 1 ekstra ciklus
|
||||
self.cycles += 1 # Ako se grana, to je 1 ekstra ciklus
|
||||
|
||||
def BCS(self, addr):
|
||||
self.BRANCH(addr, self.CARRY, True)
|
||||
|
||||
def BCS(self, addr): self.BRANCH(addr, self.CARRY, True)
|
||||
def BCC(self, addr): self.BRANCH(addr, self.CARRY, False)
|
||||
def BEQ(self, addr): self.BRANCH(addr, self.ZERO, True)
|
||||
def BNE(self, addr): self.BRANCH(addr, self.ZERO, False)
|
||||
def BMI(self, addr): self.BRANCH(addr, self.NEGATIVE, True)
|
||||
def BPL(self, addr): self.BRANCH(addr, self.NEGATIVE, False)
|
||||
def BVS(self, addr): self.BRANCH(addr, self.OVERFLOW, True)
|
||||
def BVC(self, addr): self.BRANCH(addr, self.OVERFLOW, False)
|
||||
def BCC(self, addr):
|
||||
self.BRANCH(addr, self.CARRY, False)
|
||||
|
||||
def BEQ(self, addr):
|
||||
self.BRANCH(addr, self.ZERO, True)
|
||||
|
||||
def BNE(self, addr):
|
||||
self.BRANCH(addr, self.ZERO, False)
|
||||
|
||||
def BMI(self, addr):
|
||||
self.BRANCH(addr, self.NEGATIVE, True)
|
||||
|
||||
def BPL(self, addr):
|
||||
self.BRANCH(addr, self.NEGATIVE, False)
|
||||
|
||||
def BVS(self, addr):
|
||||
self.BRANCH(addr, self.OVERFLOW, True)
|
||||
|
||||
def BVC(self, addr):
|
||||
self.BRANCH(addr, self.OVERFLOW, False)
|
||||
|
||||
# dissasemble address
|
||||
def disasm(self, addr):
|
||||
instruction, addressing, cycles = self._opcodes[self.memory[addr]]
|
||||
return "%04X %s %s" % (addr, instruction.__name__.lower(), self.addr_fmt[addressing](addr+1)), addr + self.ticks[addressing] + 1
|
||||
return (
|
||||
"%04X %s %s"
|
||||
% (addr, instruction.__name__.lower(), self.addr_fmt[addressing](addr + 1)),
|
||||
addr + self.ticks[addressing] + 1,
|
||||
)
|
||||
|
||||
def step(self):
|
||||
opcode = self.memory[self.pc]
|
||||
if opcode not in self._opcodes:
|
||||
print('HALT')
|
||||
print("HALT")
|
||||
for addr in self.executed:
|
||||
code, _ = self.disasm(addr)
|
||||
print(" - %s" % code)
|
||||
print(" > %04x %02x %02x" % (self.pc, self.memory[self.pc], self.memory[self.pc+1]))
|
||||
print((" - %s" % code))
|
||||
print(
|
||||
(
|
||||
" > %04x %02x %02x"
|
||||
% (self.pc, self.memory[self.pc], self.memory[self.pc + 1])
|
||||
)
|
||||
)
|
||||
|
||||
self.executed.append(self.pc)
|
||||
self.pc = self.pc + 1 & 0xFFFF
|
||||
|
@ -328,4 +584,3 @@ class CPU(object):
|
|||
self.executed = self.executed[1:]
|
||||
|
||||
self.cycles += cycles
|
||||
|
||||
|
|
|
@ -1,26 +1,37 @@
|
|||
# -*- coding: utf8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# defines orao keyboard
|
||||
|
||||
import pygame, numpy
|
||||
|
||||
_kbd = {
|
||||
0x83FE: (112, 240, 185, 39), 0x83FF: (45, 48), # [p đ š ;] [- 0]
|
||||
0x85FE: (232, 230, 190, 43), 0x85FF: (8, 94), # [č ć ž :] [BS ^]
|
||||
0x86FE: (102, 104, 103, 110), 0x86FF: (98, 118), # [f h g n] [b v]
|
||||
0x877E: (100, 97, 115, 122), 0x877F: (120, 99), # [d a s z] [x c]
|
||||
0x87BE: (108, 106, 107, 109), 0x87BF: (44, 46), # [l j k m] [, .]
|
||||
0x87DE: (101, 113, 119, 49), 0x87DF: (50, 51), # [e q w l] [2 3]
|
||||
0x87EE: (111, 105, 117, 55), 0x87EF: (56, 57), # [o i u 7] [8 9]
|
||||
0x87F6: (114, 121, 116, 54), 0x87F7: (53, 52), # [r y t 6] [5 4]
|
||||
0x87FA: (282, 283, 284, pygame.K_RCTRL), 0x87FD: (13, pygame.K_LCTRL), # [f1f2f3f4] [cr l_ctrl]
|
||||
0x87FC: (pygame.K_LEFT, pygame.K_UP, pygame.K_DOWN, pygame.K_RIGHT),
|
||||
0x87FB: (32, pygame.K_RSHIFT) # [spc l_shift]
|
||||
0x83FE: (112, 240, 185, 39),
|
||||
0x83FF: (45, 48), # [p đ š ;] [- 0]
|
||||
0x85FE: (232, 230, 190, 43),
|
||||
0x85FF: (8, 94), # [č ć ž :] [BS ^]
|
||||
0x86FE: (102, 104, 103, 110),
|
||||
0x86FF: (98, 118), # [f h g n] [b v]
|
||||
0x877E: (100, 97, 115, 122),
|
||||
0x877F: (120, 99), # [d a s z] [x c]
|
||||
0x87BE: (108, 106, 107, 109),
|
||||
0x87BF: (44, 46), # [l j k m] [, .]
|
||||
0x87DE: (101, 113, 119, 49),
|
||||
0x87DF: (50, 51), # [e q w l] [2 3]
|
||||
0x87EE: (111, 105, 117, 55),
|
||||
0x87EF: (56, 57), # [o i u 7] [8 9]
|
||||
0x87F6: (114, 121, 116, 54),
|
||||
0x87F7: (53, 52), # [r y t 6] [5 4]
|
||||
0x87FA: (282, 283, 284, pygame.K_RCTRL),
|
||||
0x87FD: (13, pygame.K_LCTRL), # [f1f2f3f4] [cr l_ctrl]
|
||||
0x87FC: (pygame.K_LEFT, pygame.K_UP, pygame.K_DOWN, pygame.K_RIGHT),
|
||||
0x87FB: (32, pygame.K_RSHIFT), # [spc l_shift]
|
||||
}
|
||||
|
||||
def listener(event, cpu):
|
||||
if event.type in [pygame.KEYDOWN, pygame.KEYUP]:
|
||||
for address, keycodes in _kbd.items():
|
||||
keys = list(map(pygame.key.get_pressed().__getitem__, keycodes))
|
||||
cpu.memory[address] = ~numpy.dot(keys, [16, 32, 64, 128][:len(keys)]) & 0xFF
|
||||
|
||||
def listener(event, cpu):
|
||||
if event.type in [pygame.KEYDOWN, pygame.KEYUP]:
|
||||
for address, keycodes in _kbd.items():
|
||||
keys = list(map(pygame.key.get_pressed().__getitem__, keycodes))
|
||||
cpu.memory[address] = (
|
||||
~numpy.dot(keys, [16, 32, 64, 128][: len(keys)]) & 0xFF
|
||||
)
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
timer = {}
|
||||
timer_pos = {}
|
||||
|
||||
def mem_listener(addr, val, cpu):
|
||||
if addr >= 0xa000 and addr <= 0xa0ff:
|
||||
timer_ix = addr & 0xff
|
||||
if timer_ix in timer:
|
||||
print('timer(%3d:%04x-%04x):duration %d cy' % (timer_ix, timer_pos[timer_ix], cpu.pc-1, cpu.cycles - timer[timer_ix] - 4))
|
||||
del timer[timer_ix]
|
||||
del timer_pos[timer_ix]
|
||||
else:
|
||||
timer[timer_ix] = cpu.cycles
|
||||
timer_pos[timer_ix] = cpu.pc+2
|
||||
if addr >= 0xA000 and addr <= 0xA0FF:
|
||||
timer_ix = addr & 0xFF
|
||||
if timer_ix in timer:
|
||||
print(
|
||||
(
|
||||
"timer(%3d:%04x-%04x):duration %d cy"
|
||||
% (
|
||||
timer_ix,
|
||||
timer_pos[timer_ix],
|
||||
cpu.pc - 1,
|
||||
cpu.cycles - timer[timer_ix] - 4,
|
||||
)
|
||||
)
|
||||
)
|
||||
del timer[timer_ix]
|
||||
del timer_pos[timer_ix]
|
||||
else:
|
||||
timer[timer_ix] = cpu.cycles
|
||||
timer_pos[timer_ix] = cpu.pc + 2
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
|
||||
terminal = pygame.Surface((256, 256), pygame.SRCALPHA, depth=32)
|
||||
terminal.fill((255, 255, 255))
|
||||
alphaarray = pygame.surfarray.pixels_alpha(terminal)
|
||||
|
||||
|
||||
def mem_listener(addr, val, cpu):
|
||||
if 0x6000 <= addr <= 0x7FFF: # Video RAM
|
||||
y, x = divmod((addr - 0x6000) * 8, 256)
|
||||
for i in range(8):
|
||||
alphaarray[x + i, y] = 255 if (val >> i) & 1 else 40 # Transparency mask
|
||||
if 0x6000 <= addr <= 0x7FFF: # Video RAM
|
||||
y, x = divmod((addr - 0x6000) * 8, 256)
|
||||
for i in range(8):
|
||||
alphaarray[x + i, y] = 255 if (val >> i) & 1 else 40 # Transparency mask
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
from .view import View
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
from .view import View
|
||||
from ..chargen import chargen_draw_str
|
||||
|
||||
|
||||
class CPUState(View):
|
||||
|
||||
def __init__(self):
|
||||
self.init_surface(pygame.Surface((2 * 8 * 8, 3 * 8), depth=24))
|
||||
#self.set_smooth_scale()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
import numpy
|
||||
from .view import View
|
||||
|
@ -30,4 +32,3 @@ class MemHeatmap(View):
|
|||
mem = cpu.memory[self.start_addr:self.start_addr + (w * h)]
|
||||
arr = numpy.reshape(mem, (h, w))
|
||||
pygame.surfarray.blit_array(self.surf, numpy.transpose(arr))
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .heatmap import MemHeatmap
|
||||
from .access_map import AccessMap
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
from .view import View
|
||||
from ..chargen import chargen_draw_str
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pygame
|
||||
|
||||
class View:
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
numpy==1.26.1
|
||||
pygame==2.5.2
|
||||
Wave==0.0.2
|
Binary file not shown.
BIN
software/Firmware/Monitor ROM v1.2 (19xx)(PEL Varazdin).rom
Normal file
BIN
software/Firmware/Monitor ROM v1.2 (19xx)(PEL Varazdin).rom
Normal file
Binary file not shown.
BIN
software/Firmware/Monitor ROM v1.3 (19xx)(PEL Varazdin).rom
Normal file
BIN
software/Firmware/Monitor ROM v1.3 (19xx)(PEL Varazdin).rom
Normal file
Binary file not shown.
BIN
software/Firmware/Orao Basic 1.2 (19xx)(PEL Varazdin).rom
Normal file
BIN
software/Firmware/Orao Basic 1.2 (19xx)(PEL Varazdin).rom
Normal file
Binary file not shown.
BIN
software/Games/Ajnc (19xx)(PEL Soft)(YU).tap
Normal file
BIN
software/Games/Ajnc (19xx)(PEL Soft)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Avion (1986)(Herceg, Emil - Kos, Igor)(YU).tap
Normal file
BIN
software/Games/Avion (1986)(Herceg, Emil - Kos, Igor)(YU).tap
Normal file
Binary file not shown.
Binary file not shown.
BIN
software/Games/Breakout (19xx)(Stan Rimox Software)(YU)(en).tap
Normal file
BIN
software/Games/Breakout (19xx)(Stan Rimox Software)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Brojke (19xx)(-)(YU).tap
Normal file
BIN
software/Games/Brojke (19xx)(-)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Crvic (1986)(PEL Soft)(YU).tap
Normal file
BIN
software/Games/Crvic (1986)(PEL Soft)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Eagle (1986)(KMI Borovo)(YU).tap
Normal file
BIN
software/Games/Eagle (1986)(KMI Borovo)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Figure Chess (1986)(KMI Borovo)(YU)(en).tap
Normal file
BIN
software/Games/Figure Chess (1986)(KMI Borovo)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Internacional Karate (19xx)(KMI Borovo)(YU).tap
Normal file
BIN
software/Games/Internacional Karate (19xx)(KMI Borovo)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Jugador (19xx)(Vuletic, Mario)(YU)(en).tap
Normal file
BIN
software/Games/Jugador (19xx)(Vuletic, Mario)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Jumping Jack (1986)(KMI Borovo)(YU)(en).tap
Normal file
BIN
software/Games/Jumping Jack (1986)(KMI Borovo)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Kuki (1986)(KMI Borovo)(YU).tap
Normal file
BIN
software/Games/Kuki (1986)(KMI Borovo)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Labirint (1985)(Bibi Soft)(YU).tap
Normal file
BIN
software/Games/Labirint (1985)(Bibi Soft)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Labirint M (19xx)(-)(YU).tap
Normal file
BIN
software/Games/Labirint M (19xx)(-)(YU).tap
Normal file
Binary file not shown.
Binary file not shown.
BIN
software/Games/Manic Miner (19xx)(Mihailovic, Nenad)(YU)(en).tap
Normal file
BIN
software/Games/Manic Miner (19xx)(Mihailovic, Nenad)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Match Fishing (1986)(KMI Borovo)(YU)(en).tap
Normal file
BIN
software/Games/Match Fishing (1986)(KMI Borovo)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Memo (19xx)(PEL Soft)(YU).tap
Normal file
BIN
software/Games/Memo (19xx)(PEL Soft)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Memo (19xx)(PEL Soft)(YU)[a].tap
Normal file
BIN
software/Games/Memo (19xx)(PEL Soft)(YU)[a].tap
Normal file
Binary file not shown.
BIN
software/Games/Nevidljivi (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
BIN
software/Games/Nevidljivi (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
Binary file not shown.
BIN
software/Games/Obelix (19xx)(KMI Borovo)(YU)(en).tap
Normal file
BIN
software/Games/Obelix (19xx)(KMI Borovo)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Othello (1985)(Ivkovic, Sasa)(YU).tap
Normal file
BIN
software/Games/Othello (1985)(Ivkovic, Sasa)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Pac-Man (19xx)(Ivkovic, Sasa)(YU).tap
Normal file
BIN
software/Games/Pac-Man (19xx)(Ivkovic, Sasa)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Pcelica Maja (19xx)(-)(YU).tap
Normal file
BIN
software/Games/Pcelica Maja (19xx)(-)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Pomorska Bitka (19xx)(-)(YU).tap
Normal file
BIN
software/Games/Pomorska Bitka (19xx)(-)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Reversi (19xx)(-)(YU)(en).tap
Normal file
BIN
software/Games/Reversi (19xx)(-)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Sokoban (19xx)(J.P.)(YU)(en).tap
Normal file
BIN
software/Games/Sokoban (19xx)(J.P.)(YU)(en).tap
Normal file
Binary file not shown.
BIN
software/Games/Space Invaders (19xx)(PEL Soft)(YU).tap
Normal file
BIN
software/Games/Space Invaders (19xx)(PEL Soft)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Strip Ainc (1985)(Bistrovic, Z.)(YU).tap
Normal file
BIN
software/Games/Strip Ainc (1985)(Bistrovic, Z.)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Strip Game Ainc (19xx)(KMI Borovo)(YU).tap
Normal file
BIN
software/Games/Strip Game Ainc (19xx)(KMI Borovo)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Ukleti Dvorac (19xx)(-)(YU).tap
Normal file
BIN
software/Games/Ukleti Dvorac (19xx)(-)(YU).tap
Normal file
Binary file not shown.
BIN
software/Games/Zid (1985)(PEL Zabavni Programi)(YU).tap
Normal file
BIN
software/Games/Zid (1985)(PEL Zabavni Programi)(YU).tap
Normal file
Binary file not shown.
BIN
software/Pel_Varazdin_Orao_TOSEC_2012_04_23.zip
Normal file
BIN
software/Pel_Varazdin_Orao_TOSEC_2012_04_23.zip
Normal file
Binary file not shown.
66
software/README.md
Normal file
66
software/README.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
# TOSEC: Pel Varazdin Orao
|
||||
|
||||
via https://archive.org/details/Pel_Varazdin_Orao_TOSEC_2012_04_23
|
||||
|
||||
Orao (en. Eagle) was an 8-bit computer developed by PEL Varaždin in 1984. It was used as a standard primary school computer in Croatia and Vojvodina from 1985 to 1991. Orao (code named YU102) was designed by Miroslav Kocijan to supersede Galeb (code named YU101). The goal was to make a better computer, yet with less components, easier to produce and less expensive. Originally the Motorola 6809 microprocessor was planned for the CPU but was abandoned for MOS 6502 due to its significantly lower cost.
|
||||
|
||||
There are 50 images of disks for the Pel Varazdin Orao, including games, applications, and firmware.
|
||||
|
||||
Added on: 2013-02-28 05:29:33
|
||||
Identifier: Pel_Varazdin_Orao_TOSEC_2012_04_23
|
||||
|
||||
# listing
|
||||
|
||||
## Firmware
|
||||
- Eagle Extended Basic v1.0 (1985)(PEL Varazdin).rom
|
||||
- Monitor ROM v1.2 (19xx)(PEL Varazdin).rom
|
||||
- Monitor ROM v1.3 (19xx)(PEL Varazdin).rom
|
||||
- Orao Basic 1.2 (19xx)(PEL Varazdin).rom
|
||||
|
||||
## Games
|
||||
- Ajnc (19xx)(PEL Soft)(YU).tap
|
||||
- Avion (1986)(Herceg, Emil - Kos, Igor)(YU).tap
|
||||
- Boulder Dash (19xx)(Mihailovic, Nenad - Dapjas, Mihajlo)(YU)(en).tap
|
||||
- Breakout (19xx)(Stan Rimox Software)(YU)(en).tap
|
||||
- Brojke (19xx)(-)(YU).tap
|
||||
- Crvic (1986)(PEL Soft)(YU).tap
|
||||
- Eagle (1986)(KMI Borovo)(YU).tap
|
||||
- Figure Chess (1986)(KMI Borovo)(YU)(en).tap
|
||||
- Internacional Karate (19xx)(KMI Borovo)(YU).tap
|
||||
- Jugador (19xx)(Vuletic, Mario)(YU)(en).tap
|
||||
- Jumping Jack (1986)(KMI Borovo)(YU)(en).tap
|
||||
- Kuki (1986)(KMI Borovo)(YU).tap
|
||||
- Labirint (1985)(Bibi Soft)(YU).tap
|
||||
- Labirint M (19xx)(-)(YU).tap
|
||||
- Magicni Kvadrat (1985)(Ranogajec, Mario - Korpar, Boris)(YU).tap
|
||||
- Manic Miner (19xx)(Mihailovic, Nenad)(YU)(en).tap
|
||||
- Match Fishing (1986)(KMI Borovo)(YU)(en).tap
|
||||
- Memo (19xx)(PEL Soft)(YU).tap
|
||||
- Memo (19xx)(PEL Soft)(YU)[a].tap
|
||||
- Nevidljivi (1987)(Suzy Soft)(YU)[orao no.1].tap
|
||||
- Obelix (19xx)(KMI Borovo)(YU)(en).tap
|
||||
- Othello (1985)(Ivkovic, Sasa)(YU).tap
|
||||
- Pac-Man (19xx)(Ivkovic, Sasa)(YU).tap
|
||||
- Pcelica Maja (19xx)(-)(YU).tap
|
||||
- Pomorska Bitka (19xx)(-)(YU).tap
|
||||
- Reversi (19xx)(-)(YU)(en).tap
|
||||
- Sokoban (19xx)(J.P.)(YU)(en).tap
|
||||
- Space Invaders (19xx)(PEL Soft)(YU).tap
|
||||
- Strip Ainc (1985)(Bistrovic, Z.)(YU).tap
|
||||
- Strip Game Ainc (19xx)(KMI Borovo)(YU).tap
|
||||
- Ukleti Dvorac (19xx)(-)(YU).tap
|
||||
- Zid (1985)(PEL Zabavni Programi)(YU).tap
|
||||
|
||||
## Various
|
||||
- 6502 Step v1.0 (19xx)(-).tap
|
||||
- Crtanje (1987)(Suzy Soft)(YU)[orao no.1].tap
|
||||
- Demo Grafika (1985)(KMI Borovo)(YU).tap
|
||||
- Mikroracunalo Orao (1988)(PEL Varazdin)(YU)(Tape 1 of 2).tap
|
||||
- Mikroracunalo Orao (1988)(PEL Varazdin)(YU)(Tape 2 of 2).tap
|
||||
- Podsjetnik (1987)(Suzy Soft)(YU)[orao no.1].tap
|
||||
- Porno (19xx)(-)(YU).tap
|
||||
- Sintetizator Zvuka (1987)(Suzy Soft)(YU)[orao no.1].tap
|
||||
- Tornjevi (19xx)(Tom)(YU).tap
|
||||
- Znakovi (1987)(Suzy Soft)(YU)[orao no.1].tap
|
||||
|
BIN
software/Various/6502 Step v1.0 (19xx)(-).tap
Normal file
BIN
software/Various/6502 Step v1.0 (19xx)(-).tap
Normal file
Binary file not shown.
BIN
software/Various/Crtanje (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
BIN
software/Various/Crtanje (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
Binary file not shown.
BIN
software/Various/Demo Grafika (1985)(KMI Borovo)(YU).tap
Normal file
BIN
software/Various/Demo Grafika (1985)(KMI Borovo)(YU).tap
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
software/Various/Podsjetnik (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
BIN
software/Various/Podsjetnik (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
Binary file not shown.
BIN
software/Various/Porno (19xx)(-)(YU).tap
Normal file
BIN
software/Various/Porno (19xx)(-)(YU).tap
Normal file
Binary file not shown.
Binary file not shown.
BIN
software/Various/Tornjevi (19xx)(Tom)(YU).tap
Normal file
BIN
software/Various/Tornjevi (19xx)(Tom)(YU).tap
Normal file
Binary file not shown.
BIN
software/Various/Znakovi (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
BIN
software/Various/Znakovi (1987)(Suzy Soft)(YU)[orao no.1].tap
Normal file
Binary file not shown.
Loading…
Reference in a new issue