python 2to3 updates
This commit is contained in:
parent
04a34eaf44
commit
6ace9e95b3
13 changed files with 522 additions and 211 deletions
|
@ -62,7 +62,5 @@ Then press F8 to load and start program.
|
||||||
Known bugs
|
Known bugs
|
||||||
----------
|
----------
|
||||||
|
|
||||||
- Pygame and Pulseaudio crash occasionally. - it seems that this
|
- Pygame and Pulseaudio crash occasionally. Please report any issues you have.
|
||||||
fork is less prone to lock-ups and **pygame*** crashes.
|
|
||||||
Please report any issues you have.
|
|
||||||
- no error checking for input `.prg` file
|
- no error checking for input `.prg` file
|
||||||
|
|
79
orao.py
79
orao.py
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/python2
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame, numpy, sys, datetime
|
import pygame, numpy, sys, datetime
|
||||||
from orao.cpu import CPU
|
from orao.cpu import CPU
|
||||||
|
@ -27,7 +27,7 @@ pygame.init()
|
||||||
pygame.time.set_timer(pygame.USEREVENT + 1, 40)
|
pygame.time.set_timer(pygame.USEREVENT + 1, 40)
|
||||||
|
|
||||||
# create CPU
|
# 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.channel = pygame.mixer.Channel(0)
|
||||||
cpu.store_mem_listeners.append(video_mem_listener)
|
cpu.store_mem_listeners.append(video_mem_listener)
|
||||||
cpu.store_mem_listeners.append(timer_mem_listener)
|
cpu.store_mem_listeners.append(timer_mem_listener)
|
||||||
|
@ -38,39 +38,46 @@ chargen_init(cpu.memory[0xE000:])
|
||||||
view_cpu_state = CPUState()
|
view_cpu_state = CPUState()
|
||||||
|
|
||||||
# ram zero page & stack
|
# 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)
|
view_zp.listen(cpu)
|
||||||
|
|
||||||
# user ram view
|
# 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)
|
view_ram.listen(cpu)
|
||||||
|
|
||||||
# rom access view
|
# 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_rom.listen(cpu)
|
||||||
|
|
||||||
view_screen = MicroMemView(start_addr=0x6000, size=0x2000, disp_width=32)
|
view_screen = MicroMemView(start_addr=0x6000, size=0x2000, disp_width=32)
|
||||||
view_screen.listen(cpu)
|
view_screen.listen(cpu)
|
||||||
|
|
||||||
# status lines
|
# 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))
|
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
|
# setup screen
|
||||||
screen = pygame.display.set_mode((
|
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
|
terminal.get_width() * 2
|
||||||
))
|
+ 2
|
||||||
pygame.display.set_caption('Orao Emulator v0.1')
|
+ 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)
|
lc = (0xFF, 0xCC, 0x00)
|
||||||
chargen_draw_str(status_line, 0, 16, 'F12:', color=lc)
|
chargen_draw_str(status_line, 0, 16, "F12:", color=lc)
|
||||||
chargen_draw_str(status_line, 24+8, 16, ' SCREENSHOT')
|
chargen_draw_str(status_line, 24 + 8, 16, " SCREENSHOT")
|
||||||
|
|
||||||
if MEM_LOAD_PRG is not None:
|
if MEM_LOAD_PRG is not None:
|
||||||
chargen_draw_str(status_line, 0, 24, 'F8:', color=lc)
|
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, 24, 24, " %s" % MEM_LOAD_PRG)
|
||||||
|
|
||||||
|
|
||||||
def render_frame(frame_time_ms):
|
def render_frame(frame_time_ms):
|
||||||
view_cpu_state.render(cpu, frame_time_ms)
|
view_cpu_state.render(cpu, frame_time_ms)
|
||||||
|
@ -82,8 +89,8 @@ def render_frame(frame_time_ms):
|
||||||
# blit
|
# blit
|
||||||
screen.fill((0, 0, 0))
|
screen.fill((0, 0, 0))
|
||||||
screen.blit(pygame.transform.scale(terminal, (512, 512)), [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))
|
chargen_draw_str(status_line, 0, 8, "Speed: {0:.2f} MHz".format(ratio))
|
||||||
screen.blit(status_line, [0, 512+1])
|
screen.blit(status_line, [0, 512 + 1])
|
||||||
x = 512 + 1
|
x = 512 + 1
|
||||||
y = 0
|
y = 0
|
||||||
cx, y = view_cpu_state.blit(screen, [x, y], scale=2)
|
cx, y = view_cpu_state.blit(screen, [x, y], scale=2)
|
||||||
|
@ -95,12 +102,13 @@ def render_frame(frame_time_ms):
|
||||||
y2 += 5
|
y2 += 5
|
||||||
_, _ = view_rom.blit(screen, [x, y2], scale=1)
|
_, _ = 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.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.write_map.surf, (512, 512)), [0, 0])
|
||||||
|
|
||||||
# finish rendering
|
# finish rendering
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
|
|
||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
|
@ -109,7 +117,7 @@ while running:
|
||||||
for i in range(5000):
|
for i in range(5000):
|
||||||
cpu.step()
|
cpu.step()
|
||||||
|
|
||||||
time_elapsed = (datetime.datetime.now()-before).microseconds + 1
|
time_elapsed = (datetime.datetime.now() - before).microseconds + 1
|
||||||
clock.tick()
|
clock.tick()
|
||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
|
@ -131,13 +139,13 @@ while running:
|
||||||
if pkeys[pygame.K_F8]:
|
if pkeys[pygame.K_F8]:
|
||||||
if MEM_LOAD_PRG is None:
|
if MEM_LOAD_PRG is None:
|
||||||
break
|
break
|
||||||
print("LOADING: %s" % MEM_LOAD_PRG)
|
print(("LOADING: %s" % MEM_LOAD_PRG))
|
||||||
ba = bytearray(open(MEM_LOAD_PRG, "rb").read())
|
ba = bytearray(open(MEM_LOAD_PRG, "rb").read())
|
||||||
|
|
||||||
# read load address
|
# read load address
|
||||||
addr = ba[1] * 256 + ba[0]
|
addr = ba[1] * 256 + ba[0]
|
||||||
ba = ba[2:]
|
ba = ba[2:]
|
||||||
print('Loadaddr: %04x' % addr)
|
print(("Loadaddr: %04x" % addr))
|
||||||
|
|
||||||
# load file to memory
|
# load file to memory
|
||||||
for i in range(0, len(ba)):
|
for i in range(0, len(ba)):
|
||||||
|
@ -150,22 +158,33 @@ while running:
|
||||||
|
|
||||||
if pkeys[pygame.K_F12]:
|
if pkeys[pygame.K_F12]:
|
||||||
now = datetime.datetime.now() # current date and time
|
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:
|
if event.type == pygame.USEREVENT + 1:
|
||||||
render_frame(clock.get_time())
|
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():
|
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.channel.queue(pygame.sndarray.make_sound(numpy.uint8(cpu.sndbuf)))
|
||||||
cpu.sndbuf = []
|
cpu.sndbuf = []
|
||||||
|
|
||||||
overshoot = cpu.cycles - previous_loop_cycles - time_elapsed
|
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
|
ratio = 1.0 * (cpu.cycles - previous_loop_cycles) / time_elapsed
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
chars = None
|
chars = None
|
||||||
|
|
||||||
|
@ -5,7 +6,6 @@ def chargen_init(char_data):
|
||||||
global chars
|
global chars
|
||||||
chars = char_data
|
chars = char_data
|
||||||
|
|
||||||
|
|
||||||
def chargen_draw_char(surf, px, py, ch, color=(0, 255, 0), bg=(0, 0, 0)):
|
def chargen_draw_char(surf, px, py, ch, color=(0, 255, 0), bg=(0, 0, 0)):
|
||||||
char_loc = (ord(ch) - 32) * 8
|
char_loc = (ord(ch) - 32) * 8
|
||||||
for y in range(8):
|
for y in range(8):
|
||||||
|
|
505
orao/cpu.py
505
orao/cpu.py
|
@ -1,61 +1,196 @@
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
class CPU(object):
|
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
|
alphaarray = None
|
||||||
store_mem_listeners = []
|
store_mem_listeners = []
|
||||||
read_mem_listeners = []
|
read_mem_listeners = []
|
||||||
|
|
||||||
def __init__(self, memory):
|
def __init__(self, memory):
|
||||||
s, self.tape_out, self.filename, self.samples = self, None, None, 0
|
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.cycles, s.pc, s.flags, s.sp, s.a, s.x, s.y = 0, 0xFF89, 48, 0xFF, 0, 0, 0
|
||||||
s.executed = []
|
s.executed = []
|
||||||
|
|
||||||
s._opcodes = { 0x00:(s.BRK,s.no,7), 0x01:(s.ORA,s.ix,6), 0x05:(s.ORA,s.zp,3),
|
s._opcodes = {
|
||||||
0x06:(s.ASL,s.zp,5), 0x08:(s.PHP,s.no,3), 0x09:(s.ORA,s.im,2), 0x0a:(s.ASL,s.no,2),
|
0x00: (s.BRK, s.no, 7),
|
||||||
0x0d:(s.ORA,s.ab,4), 0x0e:(s.ASL,s.ab,6), 0x10:(s.BPL,s.re,2), 0x11:(s.ORA,s.iy,6),
|
0x01: (s.ORA, s.ix, 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),
|
0x05: (s.ORA, s.zp, 3),
|
||||||
0x1d:(s.ORA,s.ax,5), 0x1e:(s.ASL,s.ax,7), 0x20:(s.JSR,s.jm,6), 0x21:(s.AND,s.ix,6),
|
0x06: (s.ASL, s.zp, 5),
|
||||||
0x24:(s.BIT,s.zp,3), 0x25:(s.AND,s.zp,3), 0x26:(s.ROL,s.zp,5), 0x28:(s.PLP,s.no,4),
|
0x08: (s.PHP, s.no, 3),
|
||||||
0x29:(s.AND,s.im,2), 0x2a:(s.ROL,s.no,2), 0x2c:(s.BIT,s.ab,4), 0x2d:(s.AND,s.ab,4),
|
0x09: (s.ORA, s.im, 2),
|
||||||
0x2e:(s.ROL,s.ab,6), 0x30:(s.BMI,s.re,2), 0x31:(s.AND,s.iy,6), 0x35:(s.AND,s.zx,4),
|
0x0A: (s.ASL, s.no, 2),
|
||||||
0x36:(s.ROL,s.zx,6), 0x38:(s.SEC,s.no,2), 0x39:(s.AND,s.ay,5), 0x3d:(s.AND,s.ax,5),
|
0x0D: (s.ORA, s.ab, 4),
|
||||||
0x3e:(s.ROL,s.ax,7), 0x40:(s.RTI,s.no,6), 0x41:(s.EOR,s.ix,6), 0x45:(s.EOR,s.zp,3),
|
0x0E: (s.ASL, s.ab, 6),
|
||||||
0x46:(s.LSR,s.zp,5), 0x48:(s.PHA,s.no,3), 0x49:(s.EOR,s.im,2), 0x4a:(s.LSR,s.no,2),
|
0x10: (s.BPL, s.re, 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),
|
0x11: (s.ORA, s.iy, 6),
|
||||||
0x51:(s.EOR,s.iy,6), 0x55:(s.EOR,s.zx,4), 0x56:(s.LSR,s.zx,6), 0x58:(s.CLI,s.no,2),
|
0x15: (s.ORA, s.zx, 4),
|
||||||
0x59:(s.EOR,s.ay,5), 0x5d:(s.EOR,s.ax,5), 0x5e:(s.LSR,s.ax,7), 0x60:(s.RTS,s.no,6),
|
0x16: (s.ASL, s.zx, 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),
|
0x18: (s.CLC, s.no, 2),
|
||||||
0x69:(s.ADC,s.im,2), 0x6a:(s.ROR,s.no,2), 0x6c:(s.JMP,s.id,5), 0x6d:(s.ADC,s.ab,4),
|
0x19: (s.ORA, s.ay, 5),
|
||||||
0x6e:(s.ROR,s.ab,6), 0x70:(s.BVS,s.re,2), 0x71:(s.ADC,s.iy,6), 0x75:(s.ADC,s.zx,4),
|
0x1D: (s.ORA, s.ax, 5),
|
||||||
0x76:(s.ROR,s.zx,6), 0x78:(s.SEI,s.no,2), 0x79:(s.ADC,s.ay,5), 0x7d:(s.ADC,s.ax,5),
|
0x1E: (s.ASL, s.ax, 7),
|
||||||
0x7e:(s.ROR,s.ax,7), 0x81:(s.STA,s.ix,6), 0x84:(s.STY,s.zp,3), 0x85:(s.STA,s.zp,3),
|
0x20: (s.JSR, s.jm, 6),
|
||||||
0x86:(s.STX,s.zp,3), 0x88:(s.DEY,s.no,2), 0x8a:(s.TXA,s.no,2), 0x8c:(s.STY,s.ab,4),
|
0x21: (s.AND, s.ix, 6),
|
||||||
0x8d:(s.STA,s.ab,4), 0x8e:(s.STX,s.ab,4), 0x90:(s.BCC,s.re,2), 0x91:(s.STA,s.iy,6),
|
0x24: (s.BIT, s.zp, 3),
|
||||||
0x94:(s.STY,s.zx,4), 0x95:(s.STA,s.zx,4), 0x96:(s.STX,s.zy,4), 0x98:(s.TYA,s.no,2),
|
0x25: (s.AND, s.zp, 3),
|
||||||
0x99:(s.STA,s.ay,5), 0x9a:(s.TXS,s.no,2), 0x9d:(s.STA,s.ax,5), 0xa0:(s.LDY,s.im,2),
|
0x26: (s.ROL, s.zp, 5),
|
||||||
0xa1:(s.LDA,s.ix,6), 0xa2:(s.LDX,s.im,2), 0xa4:(s.LDY,s.zp,3), 0xa5:(s.LDA,s.zp,3),
|
0x28: (s.PLP, s.no, 4),
|
||||||
0xa6:(s.LDX,s.zp,3), 0xa8:(s.TAY,s.no,2), 0xa9:(s.LDA,s.im,2), 0xaa:(s.TAX,s.no,2),
|
0x29: (s.AND, s.im, 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),
|
0x2A: (s.ROL, s.no, 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),
|
0x2C: (s.BIT, s.ab, 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),
|
0x2D: (s.AND, s.ab, 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),
|
0x2E: (s.ROL, s.ab, 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),
|
0x30: (s.BMI, s.re, 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),
|
0x31: (s.AND, s.iy, 6),
|
||||||
0xce:(s.DEC,s.ab,6), 0xd0:(s.BNE,s.re,2), 0xd1:(s.CMP,s.iy,6), 0xd5:(s.CMP,s.zx,4),
|
0x35: (s.AND, 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),
|
0x36: (s.ROL, s.zx, 6),
|
||||||
0xde:(s.DEC,s.ax,7), 0xe0:(s.CPX,s.im,2), 0xe1:(s.SBC,s.ix,6), 0xe4:(s.CPX,s.zp,3),
|
0x38: (s.SEC, s.no, 2),
|
||||||
0xe5:(s.SBC,s.zp,3), 0xe6:(s.INC,s.zp,5), 0xe8:(s.INX,s.no,2), 0xe9:(s.SBC,s.im,2),
|
0x39: (s.AND, s.ay, 5),
|
||||||
0xea:(s.NOP,s.no,2), 0xec:(s.CPX,s.ab,4), 0xed:(s.SBC,s.ab,4), 0xee:(s.INC,s.ab,6),
|
0x3D: (s.AND, s.ax, 5),
|
||||||
0xf0:(s.BEQ,s.re,2), 0xf1:(s.SBC,s.iy,6), 0xf5:(s.SBC,s.zx,4), 0xf6:(s.INC,s.zx,6),
|
0x3E: (s.ROL, s.ax, 7),
|
||||||
0xf8:(s.SED,s.no,2), 0xf9:(s.SBC,s.ay,5), 0xfd:(s.SBC,s.ax,5), 0xfe:(s.INC,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.ticks = {s.im: 1, s.zp: 1, s.zx: 1, s.zy: 1, s.ab: 2, s.ax: 2, s.no: 0,
|
s.im: 1,
|
||||||
s.ay: 2, s.jm: 2, s.id: 2, s.ix: 1, s.iy: 1, s.re: 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.addr_fmt = {
|
||||||
s.im: lambda addr: "#$%02X" % s.memory[addr],
|
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),
|
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):
|
def set_flag(self, flag, boolean):
|
||||||
self.flags = self.flags | flag if boolean else self.flags & ~(flag)
|
self.flags = self.flags | flag if boolean else self.flags & ~(flag)
|
||||||
|
@ -83,9 +219,11 @@ class CPU(object):
|
||||||
self.set_flag(self.NEGATIVE, src & 0x80)
|
self.set_flag(self.NEGATIVE, src & 0x80)
|
||||||
return src
|
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]).rstrip())
|
def get_filename(self):
|
||||||
|
return "wav/{0}.WAV".format(str(self.memory[592:602]).rstrip())
|
||||||
|
|
||||||
def speaker(self):
|
def speaker(self):
|
||||||
self.flipflop ^= 1
|
self.flipflop ^= 1
|
||||||
|
@ -98,17 +236,21 @@ class CPU(object):
|
||||||
def get_byte(self, addr):
|
def get_byte(self, addr):
|
||||||
if addr == 0x87FF: # Adresa ulaza kasetofona
|
if addr == 0x87FF: # Adresa ulaza kasetofona
|
||||||
if not self.tape:
|
if not self.tape:
|
||||||
self.tape = (255*(ord(j)>128) for i in \
|
self.tape = (
|
||||||
wave.open(self.get_filename()).readframes(2**24) for j in 2*i)
|
255 * (ord(j) > 128)
|
||||||
|
for i in wave.open(self.get_filename()).readframes(2**24)
|
||||||
|
for j in 2 * i
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.tape.next()
|
return next(self.tape)
|
||||||
|
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self.tape = None
|
self.tape = None
|
||||||
return 0x00
|
return 0x00
|
||||||
|
|
||||||
if addr == 0x8800: self.speaker() # Zvucnik
|
if addr == 0x8800:
|
||||||
|
self.speaker() # Zvucnik
|
||||||
|
|
||||||
if addr is not None:
|
if addr is not None:
|
||||||
for listener in self.read_mem_listeners:
|
for listener in self.read_mem_listeners:
|
||||||
|
@ -121,7 +263,8 @@ class CPU(object):
|
||||||
self.a = val & 0xFF
|
self.a = val & 0xFF
|
||||||
return
|
return
|
||||||
|
|
||||||
if addr == 0x8800: self.speaker() # Zvucnik
|
if addr == 0x8800:
|
||||||
|
self.speaker() # Zvucnik
|
||||||
|
|
||||||
self.memory[addr] = val & 0xFF
|
self.memory[addr] = val & 0xFF
|
||||||
|
|
||||||
|
@ -136,23 +279,49 @@ class CPU(object):
|
||||||
self.sp = (self.sp + 1) & 0xFF
|
self.sp = (self.sp + 1) & 0xFF
|
||||||
return self.get_byte(256 + self.sp)
|
return self.get_byte(256 + self.sp)
|
||||||
|
|
||||||
def stack_push_word(self, val): map(self.stack_push, [(val >> 8) & 0xFF, val & 0xFF])
|
def stack_push_word(self, val):
|
||||||
|
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
|
# Adresni nacini
|
||||||
def im(self): return self.pc
|
def im(self):
|
||||||
def zp(self): return self.get_byte(self.pc)
|
return self.pc
|
||||||
def zx(self): return (self.zp() + self.x) & 0xFF
|
|
||||||
def zy(self): return (self.zp() + self.y) & 0xFF
|
def zp(self):
|
||||||
def ab(self): return self.get_word(self.pc)
|
return self.get_byte(self.pc)
|
||||||
def ax(self): return self._ab(self.x)
|
|
||||||
def ay(self): return self._ab(self.y)
|
def zx(self):
|
||||||
def ix(self): return self.get_word((self.zp() + self.x) & 0xFF)
|
return (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 zy(self):
|
||||||
def jm(self): return self.ab()
|
return (self.zp() + self.y) & 0xFF
|
||||||
def no(self): return None
|
|
||||||
|
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):
|
def _ab(self, diff):
|
||||||
a1 = self.ab()
|
a1 = self.ab()
|
||||||
|
@ -171,39 +340,89 @@ class CPU(object):
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Instrukcije
|
# Instrukcije
|
||||||
def TAX(self, d): self.x = self.set_nz(self.a)
|
def TAX(self, d):
|
||||||
def TXA(self, d): self.a = self.set_nz(self.x)
|
self.x = self.set_nz(self.a)
|
||||||
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 LDA(self, addr): self.a = self.set_nz(self.get_byte(addr))
|
def TXA(self, d):
|
||||||
def LDX(self, addr): self.x = self.set_nz(self.get_byte(addr))
|
self.a = self.set_nz(self.x)
|
||||||
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 TAY(self, d):
|
||||||
def ORA(self, addr): self.a = self.set_nz(self.get_byte(addr) | self.a)
|
self.y = self.set_nz(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 TYA(self, d):
|
||||||
def SEC(self, d): self.set_flag(self.CARRY, True)
|
self.a = self.set_nz(self.y)
|
||||||
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 TSX(self, d):
|
||||||
def INY(self, d): self.y = self.set_nz((self.y + 1) & 0xFF)
|
self.x = self.set_nz(self.sp)
|
||||||
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 TXS(self, d):
|
||||||
def DEC(self, addr): self.store_byte(addr, self.set_nz(self.get_byte(addr) - 1))
|
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):
|
def ASL(self, addr):
|
||||||
operand = self.get_byte(addr)
|
operand = self.get_byte(addr)
|
||||||
|
@ -217,11 +436,20 @@ class CPU(object):
|
||||||
self.set_flag(self.NEGATIVE, op & self.NEGATIVE)
|
self.set_flag(self.NEGATIVE, op & self.NEGATIVE)
|
||||||
self.set_flag(self.OVERFLOW, op & self.OVERFLOW)
|
self.set_flag(self.OVERFLOW, op & self.OVERFLOW)
|
||||||
|
|
||||||
def PHP(self, d): self.stack_push(self.flags | self.BREAK | self.UNUSED)
|
def PHP(self, d):
|
||||||
def PHA(self, d): self.stack_push(self.a)
|
self.stack_push(self.flags | self.BREAK | self.UNUSED)
|
||||||
def PLP(self, d): self.flags = self.stack_pop()
|
|
||||||
def PLA(self, d): self.a = self.set_nz(self.stack_pop())
|
def PHA(self, d):
|
||||||
def NOP(self, d): pass
|
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):
|
def ROR(self, addr):
|
||||||
value = self.get_byte(addr) >> 1 | self.get_flag(self.CARRY) * 128
|
value = self.get_byte(addr) >> 1 | self.get_flag(self.CARRY) * 128
|
||||||
|
@ -240,14 +468,17 @@ class CPU(object):
|
||||||
self.SEI(0)
|
self.SEI(0)
|
||||||
self.pc = self.get_word(0xFFFE) # IRQ
|
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):
|
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:
|
if not self.tape_out:
|
||||||
self.tape_out = wave.open(self.get_filename(), 'w')
|
self.tape_out = wave.open(self.get_filename(), "w")
|
||||||
self.tape_out.setparams((1, 1, 44100, 0, 'NONE', 'not compressed'))
|
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.writeframes(
|
||||||
|
chr(255 * self.flipflop) * (1 + (self.y > 15)) * 10
|
||||||
|
)
|
||||||
|
|
||||||
self.stack_push_word((self.pc + 1) & 0xFFFF)
|
self.stack_push_word((self.pc + 1) & 0xFFFF)
|
||||||
self.pc = addr - 2
|
self.pc = addr - 2
|
||||||
|
@ -267,49 +498,80 @@ class CPU(object):
|
||||||
self.pc = (self.pc + 1) & 0xFFFF
|
self.pc = (self.pc + 1) & 0xFFFF
|
||||||
|
|
||||||
def ADDITION(self, arg):
|
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.OVERFLOW, (~(arg ^ self.a)) & (self.a ^ result) & 0x80)
|
||||||
self.set_flag(self.CARRY, result > 255)
|
self.set_flag(self.CARRY, result > 255)
|
||||||
self.a = self.set_nz(result) & 0xFF
|
self.a = self.set_nz(result) & 0xFF
|
||||||
|
|
||||||
def ADC(self, addr): self.ADDITION(self.get_byte(addr))
|
def ADC(self, addr):
|
||||||
def SBC(self, addr): self.ADDITION(~self.get_byte(addr))
|
self.ADDITION(self.get_byte(addr))
|
||||||
|
|
||||||
|
def SBC(self, addr):
|
||||||
|
self.ADDITION(~self.get_byte(addr))
|
||||||
|
|
||||||
def COMPARE(self, what, addr):
|
def COMPARE(self, what, addr):
|
||||||
self.set_flag(self.CARRY, self.set_nz(what - self.get_byte(addr)) >= 0)
|
self.set_flag(self.CARRY, self.set_nz(what - self.get_byte(addr)) >= 0)
|
||||||
|
|
||||||
def CMP(self, addr): self.COMPARE(self.a, addr)
|
def CMP(self, addr):
|
||||||
def CPX(self, addr): self.COMPARE(self.x, addr)
|
self.COMPARE(self.a, addr)
|
||||||
def CPY(self, addr): self.COMPARE(self.y, 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):
|
def BRANCH(self, addr, flag, condition):
|
||||||
if self.get_flag(flag) is condition:
|
if self.get_flag(flag) is condition:
|
||||||
self.pc = addr
|
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):
|
||||||
def BCC(self, addr): self.BRANCH(addr, self.CARRY, False)
|
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 BEQ(self, addr):
|
||||||
def BMI(self, addr): self.BRANCH(addr, self.NEGATIVE, True)
|
self.BRANCH(addr, self.ZERO, True)
|
||||||
def BPL(self, addr): self.BRANCH(addr, self.NEGATIVE, False)
|
|
||||||
def BVS(self, addr): self.BRANCH(addr, self.OVERFLOW, True)
|
def BNE(self, addr):
|
||||||
def BVC(self, addr): self.BRANCH(addr, self.OVERFLOW, False)
|
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
|
# dissasemble address
|
||||||
def disasm(self, addr):
|
def disasm(self, addr):
|
||||||
instruction, addressing, cycles = self._opcodes[self.memory[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):
|
def step(self):
|
||||||
opcode = self.memory[self.pc]
|
opcode = self.memory[self.pc]
|
||||||
if opcode not in self._opcodes:
|
if opcode not in self._opcodes:
|
||||||
print('HALT')
|
print("HALT")
|
||||||
for addr in self.executed:
|
for addr in self.executed:
|
||||||
code, _ = self.disasm(addr)
|
code, _ = self.disasm(addr)
|
||||||
print(" - %s" % code)
|
print((" - %s" % code))
|
||||||
print(" > %04x %02x %02x" % (self.pc, self.memory[self.pc], self.memory[self.pc+1]))
|
print(
|
||||||
|
(
|
||||||
|
" > %04x %02x %02x"
|
||||||
|
% (self.pc, self.memory[self.pc], self.memory[self.pc + 1])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.executed.append(self.pc)
|
self.executed.append(self.pc)
|
||||||
self.pc = self.pc + 1 & 0xFFFF
|
self.pc = self.pc + 1 & 0xFFFF
|
||||||
|
@ -322,4 +584,3 @@ class CPU(object):
|
||||||
self.executed = self.executed[1:]
|
self.executed = self.executed[1:]
|
||||||
|
|
||||||
self.cycles += cycles
|
self.cycles += cycles
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# defines orao keyboard
|
# defines orao keyboard
|
||||||
|
|
||||||
import pygame, numpy
|
import pygame, numpy
|
||||||
|
|
||||||
_kbd = {
|
_kbd = {
|
||||||
0x83FE: (112, 240, 185, 39), 0x83FF: (45, 48), # [p đ š ;] [- 0]
|
0x83FE: (112, 240, 185, 39),
|
||||||
0x85FE: (232, 230, 190, 43), 0x85FF: (8, 94), # [č ć ž :] [BS ^]
|
0x83FF: (45, 48), # [p đ š ;] [- 0]
|
||||||
0x86FE: (102, 104, 103, 110), 0x86FF: (98, 118), # [f h g n] [b v]
|
0x85FE: (232, 230, 190, 43),
|
||||||
0x877E: (100, 97, 115, 122), 0x877F: (120, 99), # [d a s z] [x c]
|
0x85FF: (8, 94), # [č ć ž :] [BS ^]
|
||||||
0x87BE: (108, 106, 107, 109), 0x87BF: (44, 46), # [l j k m] [, .]
|
0x86FE: (102, 104, 103, 110),
|
||||||
0x87DE: (101, 113, 119, 49), 0x87DF: (50, 51), # [e q w l] [2 3]
|
0x86FF: (98, 118), # [f h g n] [b v]
|
||||||
0x87EE: (111, 105, 117, 55), 0x87EF: (56, 57), # [o i u 7] [8 9]
|
0x877E: (100, 97, 115, 122),
|
||||||
0x87F6: (114, 121, 116, 54), 0x87F7: (53, 52), # [r y t 6] [5 4]
|
0x877F: (120, 99), # [d a s z] [x c]
|
||||||
0x87FA: (282, 283, 284, pygame.K_RCTRL), 0x87FD: (13, pygame.K_LCTRL), # [f1f2f3f4] [cr l_ctrl]
|
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),
|
0x87FC: (pygame.K_LEFT, pygame.K_UP, pygame.K_DOWN, pygame.K_RIGHT),
|
||||||
0x87FB: (32, pygame.K_RSHIFT) # [spc l_shift]
|
0x87FB: (32, pygame.K_RSHIFT), # [spc l_shift]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def listener(event, cpu):
|
def listener(event, cpu):
|
||||||
if event.type in [pygame.KEYDOWN, pygame.KEYUP]:
|
if event.type in [pygame.KEYDOWN, pygame.KEYUP]:
|
||||||
for address, keycodes in _kbd.iteritems():
|
for address, keycodes in _kbd.items():
|
||||||
keys = map(pygame.key.get_pressed().__getitem__, keycodes)
|
keys = list(map(pygame.key.get_pressed().__getitem__, keycodes))
|
||||||
cpu.memory[address] = ~numpy.dot(keys, [16, 32, 64, 128][:len(keys)]) & 0xFF
|
cpu.memory[address] = (
|
||||||
|
~numpy.dot(keys, [16, 32, 64, 128][: len(keys)]) & 0xFF
|
||||||
|
)
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
timer = {}
|
timer = {}
|
||||||
timer_pos = {}
|
timer_pos = {}
|
||||||
|
|
||||||
def mem_listener(addr, val, cpu):
|
def mem_listener(addr, val, cpu):
|
||||||
if addr >= 0xa000 and addr <= 0xa0ff:
|
if addr >= 0xA000 and addr <= 0xA0FF:
|
||||||
timer_ix = addr & 0xff
|
timer_ix = addr & 0xFF
|
||||||
if timer_ix in timer:
|
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))
|
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[timer_ix]
|
||||||
del timer_pos[timer_ix]
|
del timer_pos[timer_ix]
|
||||||
else:
|
else:
|
||||||
timer[timer_ix] = cpu.cycles
|
timer[timer_ix] = cpu.cycles
|
||||||
timer_pos[timer_ix] = cpu.pc+2
|
timer_pos[timer_ix] = cpu.pc + 2
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
terminal = pygame.Surface((256, 256), pygame.SRCALPHA, depth=32)
|
terminal = pygame.Surface((256, 256), pygame.SRCALPHA, depth=32)
|
||||||
terminal.fill((255, 255, 255))
|
terminal.fill((255, 255, 255))
|
||||||
alphaarray = pygame.surfarray.pixels_alpha(terminal)
|
alphaarray = pygame.surfarray.pixels_alpha(terminal)
|
||||||
|
|
||||||
|
|
||||||
def mem_listener(addr, val, cpu):
|
def mem_listener(addr, val, cpu):
|
||||||
if 0x6000 <= addr <= 0x7FFF: # Video RAM
|
if 0x6000 <= addr <= 0x7FFF: # Video RAM
|
||||||
y, x = divmod((addr - 0x6000) * 8, 256)
|
y, x = divmod((addr - 0x6000) * 8, 256)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from .view import View
|
from .view import View
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from .view import View
|
from .view import View
|
||||||
from ..chargen import chargen_draw_str
|
from ..chargen import chargen_draw_str
|
||||||
|
|
||||||
|
|
||||||
class CPUState(View):
|
class CPUState(View):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.init_surface(pygame.Surface((2 * 8 * 8, 3 * 8), depth=24))
|
self.init_surface(pygame.Surface((2 * 8 * 8, 3 * 8), depth=24))
|
||||||
#self.set_smooth_scale()
|
#self.set_smooth_scale()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
import numpy
|
import numpy
|
||||||
from .view import View
|
from .view import View
|
||||||
|
@ -30,4 +32,3 @@ class MemHeatmap(View):
|
||||||
mem = cpu.memory[self.start_addr:self.start_addr + (w * h)]
|
mem = cpu.memory[self.start_addr:self.start_addr + (w * h)]
|
||||||
arr = numpy.reshape(mem, (h, w))
|
arr = numpy.reshape(mem, (h, w))
|
||||||
pygame.surfarray.blit_array(self.surf, numpy.transpose(arr))
|
pygame.surfarray.blit_array(self.surf, numpy.transpose(arr))
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from .heatmap import MemHeatmap
|
from .heatmap import MemHeatmap
|
||||||
from .access_map import AccessMap
|
from .access_map import AccessMap
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from .view import View
|
from .view import View
|
||||||
from ..chargen import chargen_draw_str
|
from ..chargen import chargen_draw_str
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
class View:
|
class View:
|
||||||
|
|
Loading…
Reference in a new issue