mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
Support extended-stack, code coverage, PEEKW fn in expr
This commit is contained in:
parent
dd39115296
commit
603ebac8a6
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"okemu/gval"
|
||||
//"okemu/okean240"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -206,24 +207,25 @@ func getUint16(name string, ctx map[string]interface{}) uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b *Breakpoint) Hit(ctx map[string]interface{}) bool {
|
||||
func (b *Breakpoint) Hit(parameters map[string]interface{}) bool {
|
||||
if !b.enabled {
|
||||
return false
|
||||
}
|
||||
if b.bpType == BPTypeSimplePC {
|
||||
pc := getUint16("PC", ctx)
|
||||
pc := getUint16("PC", parameters)
|
||||
if pc == b.addr {
|
||||
log.Debugf("Breakpoint Hit PC=0x%04X", b.addr)
|
||||
}
|
||||
return pc == b.addr
|
||||
} else if b.bpType == BPTypeSimpleSP {
|
||||
sp := getUint16("SP", ctx)
|
||||
sp := getUint16("SP", parameters)
|
||||
if sp >= b.addr {
|
||||
log.Debugf("Breakpoint Hit SP>=0x%04X", b.addr)
|
||||
}
|
||||
return sp >= b.addr
|
||||
}
|
||||
value, err := b.eval.EvalBool(context.Background(), ctx)
|
||||
bc := context.WithValue(context.Background(), "MEM", parameters["MEM"])
|
||||
value, err := b.eval.EvalBool(bc, parameters)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -233,7 +235,9 @@ func (b *Breakpoint) Hit(ctx map[string]interface{}) bool {
|
||||
var language gval.Language
|
||||
|
||||
func init() {
|
||||
language = gval.NewLanguage(gval.Base(), gval.Arithmetic(), gval.Bitmask(), gval.PropositionalLogic())
|
||||
language = gval.NewLanguage(gval.Base(), gval.Arithmetic(), gval.Bitmask(), gval.PropositionalLogic(),
|
||||
gval.Function("PEEKW", cfPeekW),
|
||||
)
|
||||
}
|
||||
|
||||
func (b *Breakpoint) SetExpression(expression string) error {
|
||||
@ -254,3 +258,21 @@ func (b *Breakpoint) Expression() string {
|
||||
func (b *Breakpoint) MBank() uint8 {
|
||||
return b.mBank
|
||||
}
|
||||
|
||||
func cfPeekW(ctx context.Context, arguments ...interface{}) (interface{}, error) {
|
||||
if len(arguments) != 1 {
|
||||
return nil, fmt.Errorf("expected 1 argument")
|
||||
}
|
||||
addr, ok := arguments[0].(uint)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("argument must be a uint")
|
||||
}
|
||||
memInt := ctx.Value("MEM")
|
||||
memRead, ok := memInt.(func(uint16) uint8)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("MEM must be func(uint16) uint8")
|
||||
}
|
||||
lo := memRead(uint16(addr))
|
||||
hi := memRead(uint16(addr + 1))
|
||||
return (uint16(hi) << 8) | uint16(lo), nil
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ var ctx = map[string]interface{}{
|
||||
|
||||
const exprRep = "PC=00115h and (B=5 or BC = 5)"
|
||||
const exprDst = "PC==0x00115 && (B==5 || BC == 5)"
|
||||
const exprFn = "PC=PEEKW(SP-2) AND SP>=100"
|
||||
|
||||
func Test_PatchExpression(t *testing.T) {
|
||||
ex := patchExpression(exprRep)
|
||||
@ -29,7 +30,7 @@ func Test_PatchExpression(t *testing.T) {
|
||||
|
||||
func Test_ComplexExpr(t *testing.T) {
|
||||
|
||||
b, e := NewBreakpoint(expr1)
|
||||
b, e := NewBreakpoint(expr1, 1)
|
||||
//e := b.SetExpression(exp1)
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
@ -45,7 +46,7 @@ func Test_ComplexExpr(t *testing.T) {
|
||||
const expSimplePC = "PC=00119h"
|
||||
|
||||
func Test_BPSetPC(t *testing.T) {
|
||||
b, e := NewBreakpoint(expSimplePC)
|
||||
b, e := NewBreakpoint(expSimplePC, 1)
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
} else if b != nil {
|
||||
@ -75,3 +76,12 @@ func Test_GetCtx(t *testing.T) {
|
||||
t.Errorf("PC value not found in context")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PeekWFn(t *testing.T) {
|
||||
b, e := NewBreakpoint(exprFn, 1)
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
}
|
||||
b.enabled = true
|
||||
b.Hit(ctx)
|
||||
}
|
||||
|
||||
@ -12,3 +12,12 @@ const getMachineResponse = "64K RAM, no ZX\n"
|
||||
const respErrorLoading = "ERROR loading file"
|
||||
const quitResponse = "Sayonara baby\n"
|
||||
const runUntilBPMessage = "Running until a breakpoint, key press or data sent, menu opening or other event\n"
|
||||
|
||||
var PushValueTypeName = []string{
|
||||
"default",
|
||||
"call",
|
||||
"rst",
|
||||
"push",
|
||||
"maskable_interrupt",
|
||||
"non_maskable_interrupt",
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ var commandHandlers = map[string]CommandHandler{
|
||||
"about": (*ZRCP).handleAbout,
|
||||
"clear-membreakpoints": (*ZRCP).handleClearMemBreakpoints,
|
||||
"close-all-menus": (*ZRCP).handleEmptyHandler,
|
||||
"cpu-code-coverage": (*ZRCP).handleEmptyHandler,
|
||||
"cpu-code-coverage": (*ZRCP).handleCPUCodeCoverage,
|
||||
"cpu-history": (*ZRCP).handleCPUHistory,
|
||||
"cpu-step": (*ZRCP).handleCpuStep,
|
||||
"disable-breakpoint": (*ZRCP).handleDisableBreakpoint,
|
||||
@ -239,9 +239,8 @@ func (p *ZRCP) handleDisassemble() (string, error) {
|
||||
func convertToUint16(s string) (uint16, error) {
|
||||
v := strings.TrimSpace(strings.ToUpper(s))
|
||||
base := 0
|
||||
if strings.HasSuffix(v, "h") || strings.HasSuffix(v, "H") {
|
||||
if strings.HasSuffix(v, "H") {
|
||||
v = strings.TrimSuffix(v, "H")
|
||||
v = strings.TrimSuffix(v, "h")
|
||||
base = 16
|
||||
}
|
||||
a, e := strconv.ParseUint(v, base, 16)
|
||||
@ -282,21 +281,26 @@ func (p *ZRCP) SetMemBreakpoint(param string) string {
|
||||
|
||||
func (p *ZRCP) handleCPUHistory() (string, error) {
|
||||
params := strings.Split(p.params, " ")
|
||||
if len(params) == 0 {
|
||||
return "", errors.New("error, no parameter")
|
||||
if len(params) < 1 {
|
||||
return "", errors.New("error, no parameters")
|
||||
}
|
||||
|
||||
cmd := params[0]
|
||||
nspe := errors.New("error, no second parameter")
|
||||
|
||||
switch cmd {
|
||||
|
||||
case "enabled":
|
||||
if len(params) != 2 {
|
||||
if len(params) < 2 {
|
||||
return "", nspe
|
||||
}
|
||||
p.debugger.SetCpuHistoryEnabled(params[1] == "yes")
|
||||
|
||||
case "clear":
|
||||
p.debugger.CpuHistoryClear()
|
||||
|
||||
case "started":
|
||||
if len(params) != 2 {
|
||||
if len(params) < 2 {
|
||||
return "", nspe
|
||||
}
|
||||
p.debugger.SetCpuHistoryStarted(params[1] == "yes")
|
||||
@ -322,8 +326,13 @@ func (p *ZRCP) handleCPUHistory() (string, error) {
|
||||
return p.stateResponse(history), nil
|
||||
}
|
||||
return "", errors.New("ERROR: index out of range")
|
||||
}
|
||||
case "ignrephalt":
|
||||
// ignore
|
||||
default:
|
||||
return "", errors.New("error: unknown history command: " + cmd)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (p *ZRCP) handleLoadBinary() (string, error) {
|
||||
@ -461,6 +470,19 @@ func (p *ZRCP) handleSetRegister() (string, error) {
|
||||
return "error", errors.New("invalid set register value")
|
||||
}
|
||||
switch params[0] {
|
||||
case "AF":
|
||||
state.A = uint8(val >> 8)
|
||||
state.Flags.SetFlags(uint8(val))
|
||||
case "BC":
|
||||
state.B = uint8(val >> 8)
|
||||
state.C = uint8(val)
|
||||
case "DE":
|
||||
state.D = uint8(val >> 8)
|
||||
state.E = uint8(val)
|
||||
case "HL":
|
||||
state.H = uint8(val >> 8)
|
||||
state.L = uint8(val)
|
||||
// ------------------------------
|
||||
case "SP":
|
||||
state.SP = uint16(val)
|
||||
case "PC":
|
||||
@ -469,8 +491,25 @@ func (p *ZRCP) handleSetRegister() (string, error) {
|
||||
state.IX = uint16(val)
|
||||
case "IY":
|
||||
state.IY = uint16(val)
|
||||
// ------------------------------
|
||||
case "AF'":
|
||||
state.AAlt = uint8(val >> 8)
|
||||
state.FlagsAlt.SetFlags(uint8(val))
|
||||
case "BC'":
|
||||
state.BAlt = uint8(val >> 8)
|
||||
state.CAlt = uint8(val)
|
||||
case "DE'":
|
||||
state.DAlt = uint8(val >> 8)
|
||||
state.EAlt = uint8(val)
|
||||
case "HL'":
|
||||
state.HAlt = uint8(val >> 8)
|
||||
state.LAlt = uint8(val)
|
||||
|
||||
// ------------------------------
|
||||
case "A":
|
||||
state.A = uint8(val)
|
||||
case "F":
|
||||
state.Flags.SetFlags(uint8(val))
|
||||
case "B":
|
||||
state.B = uint8(val)
|
||||
case "C":
|
||||
@ -483,6 +522,24 @@ func (p *ZRCP) handleSetRegister() (string, error) {
|
||||
state.H = uint8(val)
|
||||
case "L":
|
||||
state.L = uint8(val)
|
||||
// ------------------------------
|
||||
case "A'":
|
||||
state.AAlt = uint8(val)
|
||||
case "F'":
|
||||
state.FlagsAlt.SetFlags(uint8(val))
|
||||
case "B'":
|
||||
state.BAlt = uint8(val)
|
||||
case "C'":
|
||||
state.CAlt = uint8(val)
|
||||
case "D'":
|
||||
state.DAlt = uint8(val)
|
||||
case "E'":
|
||||
state.EAlt = uint8(val)
|
||||
case "H'":
|
||||
state.HAlt = uint8(val)
|
||||
case "L'":
|
||||
state.LAlt = uint8(val)
|
||||
// ------------------------------
|
||||
case "I":
|
||||
state.I = uint8(val)
|
||||
case "R":
|
||||
@ -537,10 +594,14 @@ func (p *ZRCP) getExtendedStack() (string, error) {
|
||||
|
||||
resp := ""
|
||||
spEnd := sp - uint16(size*2)
|
||||
es, err := p.computer.ExtendedStack()
|
||||
if err == nil {
|
||||
for i := sp; i > spEnd; i -= 2 {
|
||||
resp += fmt.Sprintf("%04XH default\n", p.computer.MemRead(i))
|
||||
resp += fmt.Sprintf("%04XH %s\n", p.computer.MemRead(i), PushValueTypeName[es[i]])
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
log.Tracef("extended-stack get: %s", resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (p *ZRCP) handleSetBreakpoint() (string, error) {
|
||||
@ -742,8 +803,47 @@ func (p *ZRCP) handleSetBreakpointPassCount() (string, error) {
|
||||
}
|
||||
|
||||
func (p *ZRCP) handleExtendedStack() (string, error) {
|
||||
if strings.HasPrefix(p.params, "get") {
|
||||
params := strings.Split(p.params, " ")
|
||||
if len(params) < 1 {
|
||||
return "", errors.New("error, not enough params")
|
||||
}
|
||||
cmd := params[0]
|
||||
if cmd == "get" {
|
||||
return p.getExtendedStack()
|
||||
} else if cmd == "enabled" {
|
||||
if len(params) < 2 {
|
||||
return "", errors.New("error, expected yes|no")
|
||||
}
|
||||
p.computer.SetExtendedStack(params[1] == "yes")
|
||||
} else {
|
||||
return "", errors.New("error, unknown sub-command: " + cmd)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// handleCPUCodeCoverage Handle commands:
|
||||
// cpu-code-coverage enabled yes
|
||||
// cpu-code-coverage enabled no
|
||||
// cpu-code-coverage clear
|
||||
func (p *ZRCP) handleCPUCodeCoverage() (string, error) {
|
||||
command := strings.Split(p.params, " ")
|
||||
if len(command) < 1 {
|
||||
return "", errors.New("error, not enough arguments")
|
||||
}
|
||||
cmd := command[0]
|
||||
resp := ""
|
||||
switch cmd {
|
||||
case "enabled":
|
||||
if len(command) < 2 {
|
||||
return "", errors.New("error, not arguments for enabled [yas|no]")
|
||||
}
|
||||
p.computer.SetCodeCoverage(command[1] == "yes")
|
||||
case "clear":
|
||||
p.computer.ClearCodeCoverage()
|
||||
case "get":
|
||||
for addr, _ := range p.computer.CodeCoverage() {
|
||||
resp += fmt.Sprintf("%04X ", addr)
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
package dezog
|
||||
|
||||
// Command - DZRP protocol command
|
||||
type Command struct {
|
||||
length uint32 // Length of the payload data. (little endian)
|
||||
sequence uint8 // Sequence number, 1-255. Increased with each command
|
||||
command uint8 // Command ID
|
||||
data []byte // Payload
|
||||
}
|
||||
|
||||
// Response - response on DZRP protocol command
|
||||
type Response struct {
|
||||
length uint32 // Length of the following data beginning with the sequence number. (little endian)
|
||||
sequence uint8 // Sequence number, same as command.
|
||||
data []byte // Payload
|
||||
}
|
||||
|
||||
// Notification - message from emulator to DEZOG
|
||||
type Notification struct {
|
||||
seqNo uint8 // Instead of Seq No.
|
||||
command uint8 // NTF_PAUSE = 1
|
||||
breakReason uint8 // Break reason: 0 = no reason (e.g. a step-over), 1 = manual break, 2 = breakpoint hit,
|
||||
// 3 = watchpoint hit read access, 4 = watchpoint hit write access, 255 = some other reason:
|
||||
//the reason string might have useful information for the user
|
||||
address uint16 // Breakpoint or watchpoint address.
|
||||
bank uint8 // The bank+1 of the breakpoint or watchpoint address.
|
||||
reason string // Null-terminated break reason string. Might in theory have almost 2^32 byte length.
|
||||
// In practice, it will be normally less than 256. If reason string is empty it will contain at
|
||||
// least a 0.
|
||||
}
|
||||
|
||||
const NTF_PAUSE = 1
|
||||
|
||||
// Notification, Break reasons
|
||||
const (
|
||||
BR_REASON_MANUAL = 1
|
||||
BR_REASON_BP_HIT = 2
|
||||
BR_REASON_WP_HIT_R = 3
|
||||
BR_REASON_WP_HIT_W = 4
|
||||
BR_REASON_OTHER = 255
|
||||
)
|
||||
|
||||
// DEZOG Commands to emulator
|
||||
const (
|
||||
CMD_INIT = 1
|
||||
CMD_CLOSE = 2
|
||||
CMD_GET_REGISTERS = 3
|
||||
CMD_SET_REGISTER = 4
|
||||
CMD_WRITE_BANK = 5
|
||||
CMD_CONTINUE = 6
|
||||
CMD_PAUSE = 7
|
||||
CMD_READ_MEM = 8
|
||||
CMD_WRITE_MEM = 9
|
||||
CMD_SET_SLOT = 10
|
||||
CMD_GET_TBBLUE_REG = 11
|
||||
CMD_SET_BORDER = 12
|
||||
CMD_SET_BREAKPOINTS = 13
|
||||
CMD_RESTORE_MEM = 14
|
||||
CMD_LOOPBACK = 15
|
||||
CMD_GET_SPRITES_PALETTE = 16
|
||||
CMD_GET_SPRITES_CLIP_WINDOW_AND_CONTROL = 17
|
||||
CMD_GET_SPRITES = 18
|
||||
CMD_GET_SPRITE_PATTERNS = 19
|
||||
CMD_READ_PORT = 20
|
||||
CMD_WRITE_PORT = 21
|
||||
CMD_EXEC_ASM = 22
|
||||
CMD_INTERRUPT_ON_OFF = 23
|
||||
CMD_ADD_BREAKPOINT = 40
|
||||
CMD_REMOVE_BREAKPOINT = 41
|
||||
CMD_ADD_WATCHPOINT = 42
|
||||
CMD_REMOVE_WATCHPOINT = 43
|
||||
CMD_READ_STATE = 50
|
||||
CMD_WRITE_STATE = 51
|
||||
)
|
||||
@ -173,6 +173,7 @@ func (c *ComputerType) getContext() map[string]interface{} {
|
||||
context["DE"] = uint16(s.D)<<8 | uint16(s.E)
|
||||
context["HL"] = uint16(s.H)<<8 | uint16(s.L)
|
||||
context["AF"] = uint16(s.A)<<8 | uint16(s.Flags.GetFlags())
|
||||
context["MEM"] = c.memory.MemRead
|
||||
return context
|
||||
}
|
||||
|
||||
@ -458,3 +459,23 @@ func (c *ComputerType) AutoLoadFloppy() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ComputerType) ClearCodeCoverage() {
|
||||
c.cpu.ClearCodeCoverage()
|
||||
}
|
||||
|
||||
func (c *ComputerType) SetCodeCoverage(enabled bool) {
|
||||
c.cpu.SetCodeCoverage(enabled)
|
||||
}
|
||||
|
||||
func (c *ComputerType) CodeCoverage() map[uint16]bool {
|
||||
return c.cpu.CodeCoverage()
|
||||
}
|
||||
|
||||
func (c *ComputerType) SetExtendedStack(enabled bool) {
|
||||
c.cpu.SetExtendedStack(enabled)
|
||||
}
|
||||
|
||||
func (c *ComputerType) ExtendedStack() ([]byte, error) {
|
||||
return c.cpu.ExtendedStack()
|
||||
}
|
||||
|
||||
@ -1,6 +1,18 @@
|
||||
package c99
|
||||
|
||||
import "okemu/z80"
|
||||
import (
|
||||
"errors"
|
||||
"okemu/z80"
|
||||
)
|
||||
|
||||
const (
|
||||
PushValueTypeDefault = iota
|
||||
PushValueTypeCall
|
||||
PushValueTypeRst
|
||||
PushValueTypePush
|
||||
PushValueTypeMaskableInt
|
||||
PushValueTypeNonMaskableInt
|
||||
)
|
||||
|
||||
type Z80 struct {
|
||||
|
||||
@ -35,6 +47,10 @@ type Z80 struct {
|
||||
|
||||
core z80.MemIoRW
|
||||
memAccess map[uint16]byte
|
||||
codeCoverageEnabled bool
|
||||
codeCoverage map[uint16]bool
|
||||
extendedStackEnabled bool
|
||||
extendedStack [65536]uint8
|
||||
}
|
||||
|
||||
const (
|
||||
@ -92,13 +108,17 @@ func New(core z80.MemIoRW) *Z80 {
|
||||
z.intPending = false
|
||||
z.nmiPending = false
|
||||
z.intData = 0
|
||||
z.codeCoverageEnabled = false
|
||||
z.codeCoverage = make(map[uint16]bool)
|
||||
return &z
|
||||
}
|
||||
|
||||
// RunInstruction executes the next instruction in memory + handles interrupts
|
||||
func (z *Z80) RunInstruction() (uint32, *map[uint16]byte) {
|
||||
z.memAccess = map[uint16]byte{}
|
||||
|
||||
if z.codeCoverageEnabled {
|
||||
z.codeCoverage[z.pc] = true
|
||||
}
|
||||
pre := z.cycleCount
|
||||
if z.isHalted {
|
||||
z.execOpcode(0x00)
|
||||
@ -223,3 +243,35 @@ func (z *Z80) getAltFlags() z80.FlagsType {
|
||||
func (z *Z80) PC() uint16 {
|
||||
return z.pc
|
||||
}
|
||||
|
||||
func (z *Z80) ClearCodeCoverage() {
|
||||
clear(z.codeCoverage)
|
||||
}
|
||||
|
||||
func (z *Z80) SetCodeCoverage(enabled bool) {
|
||||
z.codeCoverageEnabled = enabled
|
||||
if !enabled {
|
||||
clear(z.codeCoverage)
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Z80) CodeCoverage() map[uint16]bool {
|
||||
return z.codeCoverage
|
||||
}
|
||||
|
||||
func (z *Z80) SetExtendedStack(enabled bool) {
|
||||
z.extendedStackEnabled = enabled
|
||||
if enabled {
|
||||
for addr := 0; addr < 65536; addr++ {
|
||||
z.extendedStack[addr] = PushValueTypeDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Z80) ExtendedStack() ([]byte, error) {
|
||||
var err error
|
||||
if !z.extendedStackEnabled {
|
||||
err = errors.New("error, z80: ExtendedStack disabled")
|
||||
}
|
||||
return z.extendedStack[:], err
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ func (z *Z80) ww(addr uint16, val uint16) {
|
||||
func (z *Z80) pushW(val uint16) {
|
||||
z.sp -= 2
|
||||
z.ww(z.sp, val)
|
||||
z.extendedStack[z.sp] = PushValueTypePush
|
||||
}
|
||||
|
||||
func (z *Z80) popW() uint16 {
|
||||
|
||||
@ -20,6 +20,7 @@ func (z *Z80) condJump(condition bool) {
|
||||
// calls to next word in memory
|
||||
func (z *Z80) call(addr uint16) {
|
||||
z.pushW(z.pc)
|
||||
z.extendedStack[z.sp] = PushValueTypeCall
|
||||
z.pc = addr
|
||||
z.memPtr = addr
|
||||
}
|
||||
@ -1155,21 +1156,28 @@ func (z *Z80) execOpcode(opcode byte) {
|
||||
|
||||
case 0xC7:
|
||||
z.call(0x00) // rst 0
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xCF:
|
||||
z.call(0x08) // rst 1
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xD7:
|
||||
z.call(0x10) // rst 2
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xDF:
|
||||
z.call(0x18) // rst 3
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xE7:
|
||||
z.call(0x20) // rst 4
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xEF:
|
||||
z.call(0x28) // rst 5
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xF7:
|
||||
z.call(0x30) // rst 6
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xFF:
|
||||
z.call(0x38) // rst 7
|
||||
|
||||
z.extendedStack[z.sp] = PushValueTypeRst
|
||||
case 0xC5:
|
||||
z.pushW(z.bc()) // push bc
|
||||
case 0xD5:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user