Fix up some oddities in the EightBit library

This commit is contained in:
Adrian Conlon
2025-10-06 13:44:31 +01:00
parent 3ca62c908c
commit ceacac4741
30 changed files with 9775 additions and 486 deletions

View File

@@ -18,19 +18,17 @@ namespace EightBit
this.Bus.Poke(++address, value.Low);
}
protected override Register16 FetchWord()
protected override void FetchInto(Register16 into)
{
this.Intermediate.High = this.FetchByte();
this.Intermediate.Low = this.FetchByte();
return this.Intermediate;
into.High = this.FetchByte();
into.Low = this.FetchByte();
}
protected override Register16 GetWord()
protected override void GetInto(Register16 into)
{
this.Intermediate.High = this.MemoryRead();
into.High = this.MemoryRead();
_ = this.Bus.Address.Increment();
this.Intermediate.Low = this.MemoryRead();
return this.Intermediate;
into.Low = this.MemoryRead();
}
protected override Register16 GetWordPaged()
@@ -41,11 +39,10 @@ namespace EightBit
return this.Intermediate;
}
protected override Register16 PopWord()
protected override void PopInto(Register16 into)
{
this.Intermediate.High = this.Pop();
this.Intermediate.Low = this.Pop();
return this.Intermediate;
into.High = this.Pop();
into.Low = this.Pop();
}
protected override void PushWord(Register16 value)

View File

@@ -99,8 +99,8 @@ namespace EightBit
protected override byte FetchInstruction()
{
var read = this.FetchByte();
return this.HALT.Lowered() ? (byte)0 : read;
_ = this.FetchByte();
return this.HALT.Lowered() ? (byte)0 : this.Bus.Data;
}
protected static int BuildHalfCarryIndex(byte before, byte value, int calculation) => ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
@@ -176,57 +176,44 @@ namespace EightBit
this.Call();
}
protected bool CallConditional(bool condition)
protected void CallConditional(bool condition)
{
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
if (condition)
{
this.Call();
}
return condition;
}
protected virtual bool JumpConditional(bool condition)
protected virtual void JumpConditional(bool condition)
{
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
if (condition)
{
this.Jump();
}
return condition;
}
protected virtual bool JumpRelativeConditional(bool condition)
protected virtual void JumpRelativeConditional(bool condition)
{
var offset = this.FetchByte();
if (condition)
{
this.JumpRelative(offset);
}
return condition;
}
protected virtual bool ReturnConditional(bool condition)
protected virtual void ReturnConditional(bool condition)
{
if (condition)
{
this.Return();
}
return condition;
}
protected void FetchWordMEMPTR()
{
_ = this.FetchWord();
this.MEMPTR.Assign(this.Intermediate);
}
protected virtual void JumpIndirect()
{
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.Jump();
}
@@ -237,7 +224,7 @@ namespace EightBit
protected void CallIndirect()
{
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.Call();
}
@@ -262,12 +249,12 @@ namespace EightBit
protected abstract bool ConvertCondition(int flag);
protected virtual bool JumpConditionalFlag(int flag) => this.JumpConditional(this.ConvertCondition(flag));
protected virtual void JumpConditionalFlag(int flag) => this.JumpConditional(this.ConvertCondition(flag));
protected virtual bool JumpRelativeConditionalFlag(int flag) => this.JumpRelativeConditional(this.ConvertCondition(flag));
protected virtual void JumpRelativeConditionalFlag(int flag) => this.JumpRelativeConditional(this.ConvertCondition(flag));
protected virtual bool ReturnConditionalFlag(int flag) => this.ReturnConditional(this.ConvertCondition(flag));
protected virtual void ReturnConditionalFlag(int flag) => this.ReturnConditional(this.ConvertCondition(flag));
protected virtual bool CallConditionalFlag(int flag) => this.CallConditional(this.ConvertCondition(flag));
protected virtual void CallConditionalFlag(int flag) => this.CallConditional(this.ConvertCondition(flag));
}
}

View File

@@ -19,19 +19,17 @@ namespace EightBit
this.Bus.Poke(++address, value.High);
}
protected override Register16 FetchWord()
protected override void FetchInto(Register16 into)
{
this.Intermediate.Low = this.FetchByte();
this.Intermediate.High = this.FetchByte();
return this.Intermediate;
into.Low = this.FetchByte();
into.High = this.FetchByte();
}
protected override Register16 GetWord()
protected override void GetInto(Register16 into)
{
this.Intermediate.Low = this.MemoryRead();
into.Low = this.MemoryRead();
_ = this.Bus.Address.Increment();
this.Intermediate.High = this.MemoryRead();
return this.Intermediate;
into.High = this.MemoryRead();
}
protected override Register16 GetWordPaged()
@@ -42,11 +40,10 @@ namespace EightBit
return this.Intermediate;
}
protected override Register16 PopWord()
protected override void PopInto(Register16 into)
{
this.Intermediate.Low = this.Pop();
this.Intermediate.High = this.Pop();
return this.Intermediate;
into.Low = this.Pop();
into.High = this.Pop();
}
protected override void PushWord(Register16 value)

View File

@@ -224,10 +224,7 @@ namespace EightBit
return this.MemoryRead();
}
protected virtual byte MemoryRead()
{
return this.BusRead();
}
protected virtual byte MemoryRead() => this.BusRead();
protected virtual byte BusRead() => this.Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
@@ -247,18 +244,18 @@ namespace EightBit
return this.MemoryRead();
}
protected abstract Register16 GetWord();
protected abstract void GetInto(Register16 into);
protected virtual Register16 GetWord()
{
this.GetInto(this.Intermediate);
return this.Intermediate;
}
protected abstract void SetWord(Register16 value);
protected abstract Register16 GetWordPaged();
protected Register16 GetWordPaged(Register16 address)
{
this.Bus.Address.Assign(address);
return this.GetWordPaged();
}
protected Register16 GetWordPaged(byte page, byte offset)
{
this.Bus.Address.Assign(offset, page);
@@ -279,27 +276,23 @@ namespace EightBit
this.SetWordPaged(value);
}
protected abstract Register16 FetchWord();
protected abstract void FetchInto(Register16 into);
protected void FetchWordAddress()
protected Register16 FetchWord()
{
_ = this.FetchWord();
this.Bus.Address.Assign(this.Intermediate);
this.FetchInto(this.Intermediate);
return this.Intermediate;
}
protected void FetchWordAddress() => this.Bus.Address.Assign(this.FetchWord());
protected abstract void Push(byte value);
protected abstract byte Pop();
protected abstract void PushWord(Register16 value);
protected abstract Register16 PopWord();
protected Register16 GetWord(ushort address)
{
this.Bus.Address.Word = address;
return this.GetWord();
}
protected abstract void PopInto(Register16 into);
protected Register16 GetWord(Register16 address)
{
@@ -307,12 +300,6 @@ namespace EightBit
return this.GetWord();
}
protected void SetWord(ushort address, Register16 value)
{
this.Bus.Address.Word = address;
this.SetWord(value);
}
protected void SetWord(Register16 address, Register16 value)
{
this.Bus.Address.Assign(address);
@@ -323,12 +310,6 @@ namespace EightBit
protected void Jump(Register16 destination) => this.PC.Assign(destination);
protected void Call(ushort destination)
{
this.Intermediate.Word = destination;
this.Call(this.Intermediate);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Not using VB.NET")]
protected virtual void Call(Register16 destination)
{
@@ -337,6 +318,6 @@ namespace EightBit
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Not using VB.NET")]
protected virtual void Return() => this.Jump(this.PopWord());
protected virtual void Return() => this.PopInto(this.PC);
}
}

View File

@@ -20,6 +20,12 @@ namespace Intel8080.Test
public string RomDirectory { get; } = "roms";
public string Program { get; } = "8080EX1.COM";
//public string Program { get; } = "8080EX1.COM";
public string Program { get; } = "8080EXER.COM";
//public string Program { get; } = "8080EXM.COM";
//public string Program { get; } = "8080PRE.COM";
//public string Program { get; } = "CPUTEST.COM";
//public string Program { get; } = "TEST.COM";
//public string Program { get; } = "TST8080.COM";
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,535 @@
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1
title 'Preliminary Z80 tests'
; prelim.z80 - Preliminary Z80 tests
; Copyright (C) 1994 Frank D. Cringle
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
; These tests have two goals. To start with, we assume the worst and
; successively test the instructions needed to continue testing.
; Then we try to test all instructions which cannot be handled by
; zexlax - the crc-based instruction exerciser.
; Initially errors are 'reported' by jumping to 0. This should reboot
; cp/m, so if the program terminates without any output one of the
; early tests failed. Later errors are reported by outputting an
; address via the bdos conout routine. The address can be located in
; a listing of this program.
; If the program runs to completion it displays a suitable message.
;******************************************************************************
;
; Modified by Ian Bartholomew to run a preliminary test on an 8080 CPU
;
; Assemble using M80
;
;******************************************************************************
.8080
0000' aseg
org 100h
0100 3E 01 start: mvi a,1 ; test simple compares and z/nz jumps
0102 FE 02 cpi 2
0104 CA 0000 jz 0
0107 FE 01 cpi 1
0109 C2 0000 jnz 0
010C C3 0111 jmp lab0
010F 76 hlt ; emergency exit
0110 FF db 0ffh
0111 CD 0117 lab0: call lab2 ; does a simple call work?
0114 C3 0000 lab1: jmp 0 ; fail
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-1
0117 E1 lab2: pop h ; check return address
0118 7C mov a,h
0119 FE 01 cpi high lab1
011B CA 0121 jz lab3
011E C3 0000 jmp 0
0121 7D lab3: mov a,l
0122 FE 14 cpi low lab1
0124 CA 012A jz lab4
0127 C3 0000 jmp 0
; test presence and uniqueness of all machine registers
; (except ir)
012A 31 0399 lab4: lxi sp,regs1
012D F1 pop psw
012E C1 pop b
012F D1 pop d
0130 E1 pop h
0131 31 03A9 lxi sp,regs2+8
0134 E5 push h
0135 D5 push d
0136 C5 push b
0137 F5 push psw
0000 v defl 0
rept 8
lda regs2+v/2
v defl v+2
cpi v
jnz 0
endm
0138 3A 03A1 + lda regs2+v/2
013B FE 02 + cpi v
013D C2 0000 + jnz 0
0140 3A 03A2 + lda regs2+v/2
0143 FE 04 + cpi v
0145 C2 0000 + jnz 0
0148 3A 03A3 + lda regs2+v/2
014B FE 06 + cpi v
014D C2 0000 + jnz 0
0150 3A 03A4 + lda regs2+v/2
0153 FE 08 + cpi v
0155 C2 0000 + jnz 0
0158 3A 03A5 + lda regs2+v/2
015B FE 0A + cpi v
015D C2 0000 + jnz 0
0160 3A 03A6 + lda regs2+v/2
0163 FE 0C + cpi v
0165 C2 0000 + jnz 0
0168 3A 03A7 + lda regs2+v/2
016B FE 0E + cpi v
016D C2 0000 + jnz 0
0170 3A 03A8 + lda regs2+v/2
0173 FE 10 + cpi v
0175 C2 0000 + jnz 0
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-2
; test access to memory via (hl)
0178 21 03A9 lxi h,hlval
017B 7E mov a,m
017C FE A5 cpi 0a5h
017E C2 0000 jnz 0
0181 21 03AA lxi h,hlval+1
0184 7E mov a,m
0185 FE 3C cpi 03ch
0187 C2 0000 jnz 0
; test unconditional return
018A 31 0500 lxi sp,stack
018D 21 0195 lxi h,reta
0190 E5 push h
0191 C9 ret
0192 C3 0000 jmp 0
; test instructions needed for hex output
0195 3E FF reta: mvi a,0ffh
0197 E6 0F ani 0fh
0199 FE 0F cpi 0fh
019B C2 0000 jnz 0
019E 3E 5A mvi a,05ah
01A0 E6 0F ani 0fh
01A2 FE 0A cpi 0ah
01A4 C2 0000 jnz 0
01A7 0F rrc
01A8 FE 05 cpi 05h
01AA C2 0000 jnz 0
01AD 0F rrc
01AE FE 82 cpi 82h
01B0 C2 0000 jnz 0
01B3 0F rrc
01B4 FE 41 cpi 41h
01B6 C2 0000 jnz 0
01B9 0F rrc
01BA FE A0 cpi 0a0h
01BC C2 0000 jnz 0
01BF 21 1234 lxi h,01234h
01C2 E5 push h
01C3 C1 pop b
01C4 78 mov a,b
01C5 FE 12 cpi 12h
01C7 C2 0000 jnz 0
01CA 79 mov a,c
01CB FE 34 cpi 34h
01CD C2 0000 jnz 0
; from now on we can report errors by displaying an address
; test conditional call, ret, jp, jr
tcond macro flag,pcond,ncond,rel
lxi h,&flag
push h
pop psw
c&pcond lab1&pcond
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-3
jmp error
lab1&pcond: pop h
lxi h,0d7h xor &flag
push h
pop psw
c&ncond lab2&pcond
jmp error
lab2&pcond: pop h
lxi h,lab3&pcond
push h
lxi h,&flag
push h
pop psw
r&pcond
call error
lab3&pcond: lxi h,lab4&pcond
push h
lxi h,0d7h xor &flag
push h
pop psw
r&ncond
call error
lab4&pcond: lxi h,&flag
push h
pop psw
j&pcond lab5&pcond
call error
lab5&pcond: lxi h,0d7h xor &flag
push h
pop psw
j&ncond lab6&pcond
call error
lab6&pcond:
endm
tcond 1,c,nc,1
01D0 21 0001 + lxi h,&1
01D3 E5 + push h
01D4 F1 + pop psw
01D5 DC 01DB + c&c lab1&c
01D8 C3 0352 + jmp error
01DB E1 + lab1&c: pop h
01DC 21 00D6 + lxi h,0d7h xor &1
01DF E5 + push h
01E0 F1 + pop psw
01E1 D4 01E7 + c&nc lab2&c
01E4 C3 0352 + jmp error
01E7 E1 + lab2&c: pop h
01E8 21 01F5 + lxi h,lab3&c
01EB E5 + push h
01EC 21 0001 + lxi h,&1
01EF E5 + push h
01F0 F1 + pop psw
01F1 D8 + r&c
01F2 CD 0352 + call error
01F5 21 0202 + lab3&c: lxi h,lab4&c
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-4
01F8 E5 + push h
01F9 21 00D6 + lxi h,0d7h xor &1
01FC E5 + push h
01FD F1 + pop psw
01FE D0 + r&nc
01FF CD 0352 + call error
0202 21 0001 + lab4&c: lxi h,&1
0205 E5 + push h
0206 F1 + pop psw
0207 DA 020D + j&c lab5&c
020A CD 0352 + call error
020D 21 00D6 + lab5&c: lxi h,0d7h xor &1
0210 E5 + push h
0211 F1 + pop psw
0212 D2 0218 + j&nc lab6&c
0215 CD 0352 + call error
0218 + lab6&c:
tcond 4,pe,po,0
0218 21 0004 + lxi h,&4
021B E5 + push h
021C F1 + pop psw
021D EC 0223 + c&pe lab1&pe
0220 C3 0352 + jmp error
0223 E1 + lab1&pe: pop h
0224 21 00D3 + lxi h,0d7h xor &4
0227 E5 + push h
0228 F1 + pop psw
0229 E4 022F + c&po lab2&pe
022C C3 0352 + jmp error
022F E1 + lab2&pe: pop h
0230 21 023D + lxi h,lab3&pe
0233 E5 + push h
0234 21 0004 + lxi h,&4
0237 E5 + push h
0238 F1 + pop psw
0239 E8 + r&pe
023A CD 0352 + call error
023D 21 024A + lab3&pe: lxi h,lab4&pe
0240 E5 + push h
0241 21 00D3 + lxi h,0d7h xor &4
0244 E5 + push h
0245 F1 + pop psw
0246 E0 + r&po
0247 CD 0352 + call error
024A 21 0004 + lab4&pe: lxi h,&4
024D E5 + push h
024E F1 + pop psw
024F EA 0255 + j&pe lab5&pe
0252 CD 0352 + call error
0255 21 00D3 + lab5&pe: lxi h,0d7h xor &4
0258 E5 + push h
0259 F1 + pop psw
025A E2 0260 + j&po lab6&pe
025D CD 0352 + call error
0260 + lab6&pe:
tcond 040h,z,nz,1
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-5
0260 21 0040 + lxi h,&040h
0263 E5 + push h
0264 F1 + pop psw
0265 CC 026B + c&z lab1&z
0268 C3 0352 + jmp error
026B E1 + lab1&z: pop h
026C 21 0097 + lxi h,0d7h xor &040h
026F E5 + push h
0270 F1 + pop psw
0271 C4 0277 + c&nz lab2&z
0274 C3 0352 + jmp error
0277 E1 + lab2&z: pop h
0278 21 0285 + lxi h,lab3&z
027B E5 + push h
027C 21 0040 + lxi h,&040h
027F E5 + push h
0280 F1 + pop psw
0281 C8 + r&z
0282 CD 0352 + call error
0285 21 0292 + lab3&z: lxi h,lab4&z
0288 E5 + push h
0289 21 0097 + lxi h,0d7h xor &040h
028C E5 + push h
028D F1 + pop psw
028E C0 + r&nz
028F CD 0352 + call error
0292 21 0040 + lab4&z: lxi h,&040h
0295 E5 + push h
0296 F1 + pop psw
0297 CA 029D + j&z lab5&z
029A CD 0352 + call error
029D 21 0097 + lab5&z: lxi h,0d7h xor &040h
02A0 E5 + push h
02A1 F1 + pop psw
02A2 C2 02A8 + j&nz lab6&z
02A5 CD 0352 + call error
02A8 + lab6&z:
tcond 080h,m,p,0
02A8 21 0080 + lxi h,&080h
02AB E5 + push h
02AC F1 + pop psw
02AD FC 02B3 + c&m lab1&m
02B0 C3 0352 + jmp error
02B3 E1 + lab1&m: pop h
02B4 21 0057 + lxi h,0d7h xor &080h
02B7 E5 + push h
02B8 F1 + pop psw
02B9 F4 02BF + c&p lab2&m
02BC C3 0352 + jmp error
02BF E1 + lab2&m: pop h
02C0 21 02CD + lxi h,lab3&m
02C3 E5 + push h
02C4 21 0080 + lxi h,&080h
02C7 E5 + push h
02C8 F1 + pop psw
02C9 F8 + r&m
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-6
02CA CD 0352 + call error
02CD 21 02DA + lab3&m: lxi h,lab4&m
02D0 E5 + push h
02D1 21 0057 + lxi h,0d7h xor &080h
02D4 E5 + push h
02D5 F1 + pop psw
02D6 F0 + r&p
02D7 CD 0352 + call error
02DA 21 0080 + lab4&m: lxi h,&080h
02DD E5 + push h
02DE F1 + pop psw
02DF FA 02E5 + j&m lab5&m
02E2 CD 0352 + call error
02E5 21 0057 + lab5&m: lxi h,0d7h xor &080h
02E8 E5 + push h
02E9 F1 + pop psw
02EA F2 02F0 + j&p lab6&m
02ED CD 0352 + call error
02F0 + lab6&m:
; test indirect jumps
02F0 21 02F7 lxi h,lab7
02F3 E9 pchl
02F4 CD 0352 call error
; djnz (and (partially) inc a, inc hl)
02F7 3E A5 lab7: mvi a,0a5h
02F9 06 04 mvi b,4
02FB 0F lab8: rrc
02FC 05 dcr b
02FD C2 02FB jnz lab8
0300 FE 5A cpi 05ah
0302 C4 0352 cnz error
0305 06 10 mvi b,16
0307 3C lab9: inr a
0308 05 dcr b
0309 C2 0307 jnz lab9
030C FE 6A cpi 06ah
030E C4 0352 cnz error
0311 06 00 mvi b,0
0313 21 0000 lxi h,0
0316 23 lab10: inx h
0317 05 dcr b
0318 C2 0316 jnz lab10
031B 7C mov a,h
031C FE 01 cpi 1
031E C4 0352 cnz error
0321 7D mov a,l
0322 FE 00 cpi 0
0324 C4 0352 cnz error
0327 11 0332 allok: lxi d,okmsg
032A 0E 09 mvi c,9
032C CD 0005 call 5
032F C3 0000 jmp 0
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-7
0332 38 30 38 30 okmsg: db '8080 Preliminary tests complete$'
0336 20 50 72 65
033A 6C 69 6D 69
033E 6E 61 72 79
0342 20 74 65 73
0346 74 73 20 63
034A 6F 6D 70 6C
034E 65 74 65 24
; display address at top of stack and exit
0352 C1 error: pop b
0353 26 04 mvi h,high hextab
0355 78 mov a,b
0356 0F rrc
0357 0F rrc
0358 0F rrc
0359 0F rrc
035A E6 0F ani 15
035C 6F mov l,a
035D 7E mov a,m
035E CD 038A call conout
0361 78 mov a,b
0362 E6 0F ani 15
0364 6F mov l,a
0365 7E mov a,m
0366 CD 038A call conout
0369 79 mov a,c
036A 0F rrc
036B 0F rrc
036C 0F rrc
036D 0F rrc
036E E6 0F ani 15
0370 6F mov l,a
0371 7E mov a,m
0372 CD 038A call conout
0375 79 mov a,c
0376 E6 0F ani 15
0378 6F mov l,a
0379 7E mov a,m
037A CD 038A call conout
037D 3E 0D mvi a,13
037F CD 038A call conout
0382 3E 0A mvi a,10
0384 CD 038A call conout
0387 C3 0000 jmp 0
038A F5 conout: push psw
038B C5 push b
038C D5 push d
038D E5 push h
038E 0E 02 mvi c,2
0390 5F mov e,a
0391 CD 0005 call 5
0394 E1 pop h
0395 D1 pop d
0396 C1 pop b
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-8
0397 F1 pop psw
0398 C9 ret
0000 v defl 0
0399 regs1: rept 8
v defl v+2
db v
endm
0399 02 + db v
039A 04 + db v
039B 06 + db v
039C 08 + db v
039D 0A + db v
039E 0C + db v
039F 0E + db v
03A0 10 + db v
03A1 regs2: ds 8,0
03A9 A5 3C hlval: db 0a5h,03ch
; skip to next page boundary
org (($+255)/256)*256
0400 30 31 32 33 hextab: db '0123456789abcdef'
0404 34 35 36 37
0408 38 39 61 62
040C 63 64 65 66
0410 ds 240
0500 stack equ $
end start
'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE S
Macros:
TCOND
Symbols:
0327 ALLOK 038A CONOUT 0352 ERROR
0400 HEXTAB 03A9 HLVAL 0111 LAB0
0114 LAB1 0316 LAB10 01DB LAB1C
02B3 LAB1M 0223 LAB1PE 026B LAB1Z
0117 LAB2 01E7 LAB2C 02BF LAB2M
022F LAB2PE 0277 LAB2Z 0121 LAB3
01F5 LAB3C 02CD LAB3M 023D LAB3PE
0285 LAB3Z 012A LAB4 0202 LAB4C
02DA LAB4M 024A LAB4PE 0292 LAB4Z
020D LAB5C 02E5 LAB5M 0255 LAB5PE
029D LAB5Z 0218 LAB6C 02F0 LAB6M
0260 LAB6PE 02A8 LAB6Z 02F7 LAB7
02FB LAB8 0307 LAB9 0332 OKMSG
0399 REGS1 03A1 REGS2 0195 RETA
0500 STACK 0100 START 0010 V
No Fatal error(s)

View File

@@ -0,0 +1,31 @@
This folder contains 8080 CPU test programs that run under CP/M
TST8080
8080/8085 CPU Diagnostic, version 1.0, by Microcosm Associates
(Kelly Smith test)
8080PRE
Preliminary test for 8080/8085 CPU Exerciser by Ian Bartholomew
and Frank Cringles.
8080EXER
8080/8085 CPU Exerciser by Ian Bartholomew and Frank Cringles.
This is a very thorough test that generates a CRC code for each
group of tests. The program will say "Error" for every test, but
it's not actually an error. Instead, compare the reported CRC
with results from tests against real silicon. See 8080EXER.PNG in
this directory and http://www.idb.me.uk/sunhillow/8080.html. The
full test takes several hours. The "aluop <b,c,d,e,h,l,m,a>" section
takes especially long.
8080EXM
8080/80805 Exerciser "M"odified with the correct result CRCs in
the program so it can display "pass" or "fail" correctly.
CPUTEST
SuperSoft Associates CPU test from the Diagnostic II
suite. When it displays "ABCDEF..." those are actually
indications of test that have passed. Additional testing
occurs during the "Begin Timing Test" and "End Timing Test"
period. On a 2MHz 8080, the timing test period lasts about
two minutes.

View File

@@ -0,0 +1,819 @@
;***********************************************************************
; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980
;***********************************************************************
;
;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY:
;KELLY SMITH, MICROCOSM ASSOCIATES
;3055 WACO AVENUE
;SIMI VALLEY, CALIFORNIA, 93065
;(805) 527-9321 (MODEM, CP/M-NET (TM))
;(805) 527-0518 (VERBAL)
;
; Updated by Mike Douglas October, 2012
;
; Added the following tests that were missing:
; mov c,m
; mov m,c
; ana b
;
; Fixed the CPUER exit routine which did not display the
; low byte of the failure address properly.
;
; Added display of the Microcosm welcome message
;
ORG 00100H
;
JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC
;
WELCOM DB 'MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC',13,10
DB ' VERSION 1.0 (C) 1980',13,10,'$'
;
BDOS EQU 00005H ;BDOS ENTRY TO CP/M
WBOOT EQU 00000H ;RE-ENTRY TO CP/M WARM BOOT
;
;
;
;MESSAGE OUTPUT ROUTINE
;
MSG: PUSH D ;EXILE D REG.
XCHG ;SWAP H&L REGS. TO D&E REGS.
MVI C,9 ;LET BDOS KNOW WE WANT TO SEND A MESSAGE
CALL BDOS
POP D ;BACK FROM EXILE
RET
;
;
;
;CHARACTER OUTPUT ROUTINE
;
PCHAR: MVI C,2
CALL BDOS
RET
;
;
;
BYTEO: PUSH PSW
CALL BYTO1
MOV E,A
CALL PCHAR
POP PSW
CALL BYTO2
MOV E,A
JMP PCHAR
BYTO1: RRC
RRC
RRC
RRC
BYTO2: ANI 0FH
CPI 0AH
JM BYTO3
ADI 7
BYTO3: ADI 30H
RET
;
;
;
;************************************************************
; MESSAGE TABLE FOR OPERATIONAL CPU TEST
;************************************************************
;
OKCPU: DB 0DH,0AH,' CPU IS OPERATIONAL$'
;
NGCPU: DB 0DH,0AH,' CPU HAS FAILED! ERROR EXIT=$'
;
;
;
;************************************************************
; 8080/8085 CPU TEST/DIAGNOSTIC
;************************************************************
;
;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK!
;
; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI","RIM","SIM",
; AND "RST 0" THRU "RST 7"
;
;
;
;TEST JUMP INSTRUCTIONS AND FLAGS
;
CPU: LXI SP,STACK ;SET THE STACK POINTER
LXI H,WELCOM
CALL MSG
ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS
JZ J010 ;TEST "JZ"
CALL CPUER
J010: JNC J020 ;TEST "JNC"
CALL CPUER
J020: JPE J030 ;TEST "JPE"
CALL CPUER
J030: JP J040 ;TEST "JP"
CALL CPUER
J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER
J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0
JNZ J070 ;TEST "JNZ"
CALL CPUER
J070: JC J080 ;TEST "JC"
JPO J080 ;TEST "JPO"
JP J090 ;TEST "JP"
J080: CALL CPUER
J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0
JPO J100 ;TEST "JPO"
CALL CPUER
J100: JM J110 ;TEST "JM"
JZ J110 ;TEST "JZ"
JNC J120 ;TEST "JNC"
J110: CALL CPUER
J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0
JM J130 ;TEST "JM"
CALL CPUER
J130: JZ J140 ;TEST "JZ"
JC J140 ;TEST "JC"
JPO J150 ;TEST "JPO"
J140: CALL CPUER
J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0
JC J160 ;TEST "JC"
CALL CPUER
J160: JZ J170 ;TEST "JZ"
JPO J170 ;TEST "JPO"
JM AIMM ;TEST "JM"
J170: CALL CPUER
;
;
;
;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS
;
AIMM: CPI 0 ;A=F5H,C=0,Z=0
JC CPIE ;TEST "CPI" FOR RE-SET CARRY
JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
CPI 0F5H ;A=F5H,C=0,Z=1
JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI")
JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO
CPI 0FFH ;A=F5H,C=1,Z=0
JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
JC ACII ;TEST "CPI" FOR SET CARRY
CPIE: CALL CPUER
ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1
ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0
CPI 00BH
JZ SUII ;TEST "ACI"
CALL CPUER
SUII: SUI 00CH ;A=FFH,C=0
SUI 00FH ;A=F0H,C=1
CPI 0F0H
JZ SBII ;TEST "SUI"
CALL CPUER
SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1
SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0
CPI 0F0H
JZ ANII ;TEST "SBI"
CALL CPUER
ANII: ANI 055H ;A=F0H<AND>55H=50H,C=0,P=1,S=0,Z=0
CPI 050H
JZ ORII ;TEST "ANI"
CALL CPUER
ORII: ORI 03AH ;A=50H<OR>3AH=7AH,C=0,P=0,S=0,Z=0
CPI 07AH
JZ XRII ;TEST "ORI"
CALL CPUER
XRII: XRI 00FH ;A=7AH<XOR>0FH=75H,C=0,P=0,S=0,Z=0
CPI 075H
JZ C010 ;TEST "XRI"
CALL CPUER
;
;
;
;TEST CALLS AND RETURNS
;
C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1
CC CPUER ;TEST "CC"
CPO CPUER ;TEST "CPO"
CM CPUER ;TEST "CM"
CNZ CPUER ;TEST "CNZ"
CPI 000H
JZ C020 ;A=0,C=0,P=0,S=0,Z=1
CALL CPUER
C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0
CNC CPUER ;TEST "CNC"
CPE CPUER ;TEST "CPE"
CP CPUER ;TEST "CP"
CZ CPUER ;TEST "CZ"
CPI 089H
JZ C030 ;TEST FOR "CALLS" TAKING BRANCH
CALL CPUER
C030: ANI 0FFH ;SET FLAGS BACK!
CPO CPOI ;TEST "CPO"
CPI 0D9H
JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS
CALL CPUER
CPOI: RPE ;TEST "RPE"
ADI 010H ;A=99H,C=0,P=0,S=1,Z=0
CPE CPEI ;TEST "CPE"
ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0
RPO ;TEST "RPO"
CALL CPUER
CPEI: RPO ;TEST "RPO"
ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0
CM CMI ;TEST "CM"
ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0
RPE ;TEST "RPE"
CALL CPUER
CMI: RP ;TEST "RP"
ADI 080H ;A=39H,C=1,P=1,S=0,Z=0
CP TCPI ;TEST "CP"
ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0
RM ;TEST "RM"
CALL CPUER
TCPI: RM ;TEST "RM"
ADI 040H ;A=79H,C=0,P=0,S=0,Z=0
CNC CNCI ;TEST "CNC"
ADI 040H ;A=53H,C=0,P=1,S=0,Z=0
RP ;TEST "RP"
CALL CPUER
CNCI: RC ;TEST "RC"
ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0
CC CCI ;TEST "CC"
SUI 002H ;A=13H,C=0,P=0,S=0,Z=0
RNC ;TEST "RNC"
CALL CPUER
CCI: RNC ;TEST "RNC"
ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0
CNZ CNZI ;TEST "CNZ"
ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0
RC ;TEST "RC"
CALL CPUER
CNZI: RZ ;TEST "RZ"
ADI 001H ;A=00H,C=1,P=1,S=0,Z=1
CZ CZI ;TEST "CZ"
ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0
RNZ ;TEST "RNZ"
CALL CPUER
CZI: RNZ ;TEST "RNZ"
ADI 047H ;A=47H,C=0,P=1,S=0,Z=0
CPI 047H ;A=47H,C=0,P=1,S=0,Z=1
RZ ;TEST "RZ"
CALL CPUER
;
;
;
;TEST "MOV","INR",AND "DCR" INSTRUCTIONS
;
MOVI: MVI A,077H
INR A
MOV B,A
INR B
MOV C,B
DCR C
MOV D,C
MOV E,D
MOV H,E
MOV L,H
MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A
DCR A
MOV C,A
MOV E,C
MOV L,E
MOV B,L
MOV D,B
MOV H,D
MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A
MOV D,A
INR D
MOV L,D
MOV C,L
INR C
MOV H,C
MOV B,H
DCR B
MOV E,B
MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A
MOV E,A
INR E
MOV B,E
MOV H,B
INR H
MOV C,H
MOV L,C
MOV D,L
DCR D
MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A
MOV H,A
DCR H
MOV D,H
MOV B,D
MOV L,B
INR L
MOV E,L
DCR E
MOV C,E
MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A
MOV L,A
DCR L
MOV H,L
MOV E,H
MOV D,E
MOV C,D
MOV B,C
MOV A,B
CPI 077H
CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A
;
;
;
;TEST ARITHMETIC AND LOGIC INSTRUCTIONS
;
XRA A
MVI B,001H
MVI C,003H
MVI D,007H
MVI E,00FH
MVI H,01FH
MVI L,03FH
ADD B
ADD C
ADD D
ADD E
ADD H
ADD L
ADD A
CPI 0F0H
CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A
SUB B
SUB C
SUB D
SUB E
SUB H
SUB L
CPI 078H
CNZ CPUER ;TEST "SUB" B,C,D,E,H,L
SUB A
CNZ CPUER ;TEST "SUB" A
MVI A,080H
ADD A
MVI B,001H
MVI C,002H
MVI D,003H
MVI E,004H
MVI H,005H
MVI L,006H
ADC B
MVI B,080H
ADD B
ADD B
ADC C
ADD B
ADD B
ADC D
ADD B
ADD B
ADC E
ADD B
ADD B
ADC H
ADD B
ADD B
ADC L
ADD B
ADD B
ADC A
CPI 037H
CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A
MVI A,080H
ADD A
MVI B,001H
SBB B
MVI B,0FFH
ADD B
SBB C
ADD B
SBB D
ADD B
SBB E
ADD B
SBB H
ADD B
SBB L
CPI 0E0H
CNZ CPUER ;TEST "SBB" B,C,D,E,H,L
MVI A,080H
ADD A
SBB A
CPI 0FFH
CNZ CPUER ;TEST "SBB" A
MVI A,0FFH
MVI B,0FEH
MVI C,0FCH
MVI D,0EFH
MVI E,07FH
MVI H,0F4H
MVI L,0BFH
ANA B ;changed from ANA A (mwd)
ANA C
ANA D
ANA E
ANA H
ANA L
ANA A
CPI 024H
CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A
XRA A
MVI B,001H
MVI C,002H
MVI D,004H
MVI E,008H
MVI H,010H
MVI L,020H
ORA B
ORA C
ORA D
ORA E
ORA H
ORA L
ORA A
CPI 03FH
CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A
MVI A,000H
MVI H,08FH
MVI L,04FH
XRA B
XRA C
XRA D
XRA E
XRA H
XRA L
CPI 0CFH
CNZ CPUER ;TEST "XRA" B,C,D,E,H,L
XRA A
CNZ CPUER ;TEST "XRA" A
MVI B,044H
MVI C,045H
MVI D,046H
MVI E,047H
MVI H,(TEMP0 / 0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION
MVI L,(TEMP0 AND 0FFH) ;LOW BYTE OF TEST MEMORY LOCATION
MOV M,B
MVI B,000H
MOV B,M
MVI A,044H
CMP B
CNZ CPUER ;TEST "MOV" M,B AND B,M
MOV M,C ;added (mwd)
MVI C,000H ;added (mwd)
MOV C,M ;added (mwd)
MVI A,045H ;added (mwd)
CMP C ;added (mwd)
CNZ CPUER ;TEST "MOV" M,C AND C,M added (mwd)
MOV M,D
MVI D,000H
MOV D,M
MVI A,046H
CMP D
CNZ CPUER ;TEST "MOV" M,D AND D,M
MOV M,E
MVI E,000H
MOV E,M
MVI A,047H
CMP E
CNZ CPUER ;TEST "MOV" M,E AND E,M
MOV M,H
MVI H,(TEMP0 / 0FFH)
MVI L,(TEMP0 AND 0FFH)
MOV H,M
MVI A,(TEMP0 / 0FFH)
CMP H
CNZ CPUER ;TEST "MOV" M,H AND H,M
MOV M,L
MVI H,(TEMP0 / 0FFH)
MVI L,(TEMP0 AND 0FFH)
MOV L,M
MVI A,(TEMP0 AND 0FFH)
CMP L
CNZ CPUER ;TEST "MOV" M,L AND L,M
MVI H,(TEMP0 / 0FFH)
MVI L,(TEMP0 AND 0FFH)
MVI A,032H
MOV M,A
CMP M
CNZ CPUER ;TEST "MOV" M,A
ADD M
CPI 064H
CNZ CPUER ;TEST "ADD" M
XRA A
MOV A,M
CPI 032H
CNZ CPUER ;TEST "MOV" A,M
MVI H,(TEMP0 / 0FFH)
MVI L,(TEMP0 AND 0FFH)
MOV A,M
SUB M
CNZ CPUER ;TEST "SUB" M
MVI A,080H
ADD A
ADC M
CPI 033H
CNZ CPUER ;TEST "ADC" M
MVI A,080H
ADD A
SBB M
CPI 0CDH
CNZ CPUER ;TEST "SBB" M
ANA M
CNZ CPUER ;TEST "ANA" M
MVI A,025H
ORA M
CPI 037H
CNZ CPUER ;TEST "ORA" M
XRA M
CPI 005H
CNZ CPUER ;TEST "XRA" M
MVI M,055H
INR M
DCR M
ADD M
CPI 05AH
CNZ CPUER ;TEST "INR","DCR",AND "MVI" M
LXI B,12FFH
LXI D,12FFH
LXI H,12FFH
INX B
INX D
INX H
MVI A,013H
CMP B
CNZ CPUER ;TEST "LXI" AND "INX" B
CMP D
CNZ CPUER ;TEST "LXI" AND "INX" D
CMP H
CNZ CPUER ;TEST "LXI" AND "INX" H
MVI A,000H
CMP C
CNZ CPUER ;TEST "LXI" AND "INX" B
CMP E
CNZ CPUER ;TEST "LXI" AND "INX" D
CMP L
CNZ CPUER ;TEST "LXI" AND "INX" H
DCX B
DCX D
DCX H
MVI A,012H
CMP B
CNZ CPUER ;TEST "DCX" B
CMP D
CNZ CPUER ;TEST "DCX" D
CMP H
CNZ CPUER ;TEST "DCX" H
MVI A,0FFH
CMP C
CNZ CPUER ;TEST "DCX" B
CMP E
CNZ CPUER ;TEST "DCX" D
CMP L
CNZ CPUER ;TEST "DCX" H
STA TEMP0
XRA A
LDA TEMP0
CPI 0FFH
CNZ CPUER ;TEST "LDA" AND "STA"
LHLD TEMPP
SHLD TEMP0
LDA TEMPP
MOV B,A
LDA TEMP0
CMP B
CNZ CPUER ;TEST "LHLD" AND "SHLD"
LDA TEMPP+1
MOV B,A
LDA TEMP0+1
CMP B
CNZ CPUER ;TEST "LHLD" AND "SHLD"
MVI A,0AAH
STA TEMP0
MOV B,H
MOV C,L
XRA A
LDAX B
CPI 0AAH
CNZ CPUER ;TEST "LDAX" B
INR A
STAX B
LDA TEMP0
CPI 0ABH
CNZ CPUER ;TEST "STAX" B
MVI A,077H
STA TEMP0
LHLD TEMPP
LXI D,00000H
XCHG
XRA A
LDAX D
CPI 077H
CNZ CPUER ;TEST "LDAX" D AND "XCHG"
XRA A
ADD H
ADD L
CNZ CPUER ;TEST "XCHG"
MVI A,0CCH
STAX D
LDA TEMP0
CPI 0CCH
STAX D
LDA TEMP0
CPI 0CCH
CNZ CPUER ;TEST "STAX" D
LXI H,07777H
DAD H
MVI A,0EEH
CMP H
CNZ CPUER ;TEST "DAD" H
CMP L
CNZ CPUER ;TEST "DAD" H
LXI H,05555H
LXI B,0FFFFH
DAD B
MVI A,055H
CNC CPUER ;TEST "DAD" B
CMP H
CNZ CPUER ;TEST "DAD" B
MVI A,054H
CMP L
CNZ CPUER ;TEST "DAD" B
LXI H,0AAAAH
LXI D,03333H
DAD D
MVI A,0DDH
CMP H
CNZ CPUER ;TEST "DAD" D
CMP L
CNZ CPUER ;TEST "DAD" B
STC
CNC CPUER ;TEST "STC"
CMC
CC CPUER ;TEST "CMC
MVI A,0AAH
CMA
CPI 055H
CNZ CPUER ;TEST "CMA"
ORA A ;RE-SET AUXILIARY CARRY
DAA
CPI 055H
CNZ CPUER ;TEST "DAA"
MVI A,088H
ADD A
DAA
CPI 076H
CNZ CPUER ;TEST "DAA"
XRA A
MVI A,0AAH
DAA
CNC CPUER ;TEST "DAA"
CPI 010H
CNZ CPUER ;TEST "DAA"
XRA A
MVI A,09AH
DAA
CNC CPUER ;TEST "DAA"
CNZ CPUER ;TEST "DAA"
STC
MVI A,042H
RLC
CC CPUER ;TEST "RLC" FOR RE-SET CARRY
RLC
CNC CPUER ;TEST "RLC" FOR SET CARRY
CPI 009H
CNZ CPUER ;TEST "RLC" FOR ROTATION
RRC
CNC CPUER ;TEST "RRC" FOR SET CARRY
RRC
CPI 042H
CNZ CPUER ;TEST "RRC" FOR ROTATION
RAL
RAL
CNC CPUER ;TEST "RAL" FOR SET CARRY
CPI 008H
CNZ CPUER ;TEST "RAL" FOR ROTATION
RAR
RAR
CC CPUER ;TEST "RAR" FOR RE-SET CARRY
CPI 002H
CNZ CPUER ;TEST "RAR" FOR ROTATION
LXI B,01234H
LXI D,0AAAAH
LXI H,05555H
XRA A
PUSH B
PUSH D
PUSH H
PUSH PSW
LXI B,00000H
LXI D,00000H
LXI H,00000H
MVI A,0C0H
ADI 0F0H
POP PSW
POP H
POP D
POP B
CC CPUER ;TEST "PUSH PSW" AND "POP PSW"
CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW"
CPO CPUER ;TEST "PUSH PSW" AND "POP PSW"
CM CPUER ;TEST "PUSH PSW" AND "POP PSW"
MVI A,012H
CMP B
CNZ CPUER ;TEST "PUSH B" AND "POP B"
MVI A,034H
CMP C
CNZ CPUER ;TEST "PUSH B" AND "POP B"
MVI A,0AAH
CMP D
CNZ CPUER ;TEST "PUSH D" AND "POP D"
CMP E
CNZ CPUER ;TEST "PUSH D" AND "POP D"
MVI A,055H
CMP H
CNZ CPUER ;TEST "PUSH H" AND "POP H"
CMP L
CNZ CPUER ;TEST "PUSH H" AND "POP H"
LXI H,00000H
DAD SP
SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER!
LXI SP,TEMP4
DCX SP
DCX SP
INX SP
DCX SP
MVI A,055H
STA TEMP2
CMA
STA TEMP3
POP B
CMP B
CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP
CMA
CMP C
CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP
LXI H,TEMP4
SPHL
LXI H,07733H
DCX SP
DCX SP
XTHL
LDA TEMP3
CPI 077H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
LDA TEMP2
CPI 033H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
MVI A,055H
CMP L
CNZ CPUER ;TEST "SPHL" AND "XTHL"
CMA
CMP H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER
SPHL
LXI H,CPUOK
PCHL ;TEST "PCHL"
;
;
;
CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE
CALL MSG
POP H ;HL = ADDRESS FOLLOWING CALL CPUER
PUSH H
MOV A,H
CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE
POP H
MOV A,L
CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE
JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE
CALL MSG
JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD",
; AND "LDAX" INSTRUCTIONS
;
TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION
;
;
;
STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA
;
;
;
END

Binary file not shown.

View File

@@ -0,0 +1,821 @@
;***********************************************************************
; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980
;***********************************************************************
;
;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY:
;KELLY SMITH, MICROCOSM ASSOCIATES
;3055 WACO AVENUE
;SIMI VALLEY, CALIFORNIA, 93065
;(805) 527-9321 (MODEM, CP/M-NET (TM))
;(805) 527-0518 (VERBAL)
;
; Updated by Mike Douglas October, 2012
;
; Added the following tests that were missing:
; mov c,m
; mov m,c
; ana b
;
; Fixed the CPUER exit routine which did not display the
; low byte of the failure address properly.
;
; Added display of the Microcosm welcome message
;
0100 ORG 00100H
;
0100 C3B201 JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC
;
0103 4D4943524FWELCOM DB 'MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC',13,10
0132 2056455253 DB ' VERSION 1.0 (C) 1980',13,10,'$'
;
0005 = BDOS EQU 00005H ;BDOS ENTRY TO CP/M
0000 = WBOOT EQU 00000H ;RE-ENTRY TO CP/M WARM BOOT
;
;
;
;MESSAGE OUTPUT ROUTINE
;
014B D5 MSG: PUSH D ;EXILE D REG.
014C EB XCHG ;SWAP H&L REGS. TO D&E REGS.
014D 0E09 MVI C,9 ;LET BDOS KNOW WE WANT TO SEND A MESSAGE
014F CD0500 CALL BDOS
0152 D1 POP D ;BACK FROM EXILE
0153 C9 RET
;
;
;
;CHARACTER OUTPUT ROUTINE
;
0154 0E02 PCHAR: MVI C,2
0156 CD0500 CALL BDOS
0159 C9 RET
;
;
;
015A F5 BYTEO: PUSH PSW
015B CD6A01 CALL BYTO1
015E 5F MOV E,A
015F CD5401 CALL PCHAR
0162 F1 POP PSW
0163 CD6E01 CALL BYTO2
0166 5F MOV E,A
0167 C35401 JMP PCHAR
016A 0F BYTO1: RRC
016B 0F RRC
016C 0F RRC
016D 0F RRC
016E E60F BYTO2: ANI 0FH
0170 FE0A CPI 0AH
0172 FA7701 JM BYTO3
0175 C607 ADI 7
0177 C630 BYTO3: ADI 30H
0179 C9 RET
;
;
;
;************************************************************
; MESSAGE TABLE FOR OPERATIONAL CPU TEST
;************************************************************
;
017A 0D0A204350OKCPU: DB 0DH,0AH,' CPU IS OPERATIONAL$'
;
0190 0D0A204350NGCPU: DB 0DH,0AH,' CPU HAS FAILED! ERROR EXIT=$'
;
;
;
;************************************************************
; 8080/8085 CPU TEST/DIAGNOSTIC
;************************************************************
;
;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK!
;
; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI","RIM","SIM",
; AND "RST 0" THRU "RST 7"
;
;
;
;TEST JUMP INSTRUCTIONS AND FLAGS
;
01B2 31BD07 CPU: LXI SP,STACK ;SET THE STACK POINTER
01B5 210301 LXI H,WELCOM
01B8 CD4B01 CALL MSG
01BB E600 ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS
01BD CAC301 JZ J010 ;TEST "JZ"
01C0 CDA006 CALL CPUER
01C3 D2C901 J010: JNC J020 ;TEST "JNC"
01C6 CDA006 CALL CPUER
01C9 EACF01 J020: JPE J030 ;TEST "JPE"
01CC CDA006 CALL CPUER
01CF F2D501 J030: JP J040 ;TEST "JP"
01D2 CDA006 CALL CPUER
01D5 C2E401 J040: JNZ J050 ;TEST "JNZ"
01D8 DAE401 JC J050 ;TEST "JC"
01DB E2E401 JPO J050 ;TEST "JPO"
01DE FAE401 JM J050 ;TEST "JM"
01E1 C3E701 JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
01E4 CDA006 J050: CALL CPUER
01E7 C606 J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0
01E9 C2EF01 JNZ J070 ;TEST "JNZ"
01EC CDA006 CALL CPUER
01EF DAF801 J070: JC J080 ;TEST "JC"
01F2 E2F801 JPO J080 ;TEST "JPO"
01F5 F2FB01 JP J090 ;TEST "JP"
01F8 CDA006 J080: CALL CPUER
01FB C670 J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0
01FD E20302 JPO J100 ;TEST "JPO"
0200 CDA006 CALL CPUER
0203 FA0C02 J100: JM J110 ;TEST "JM"
0206 CA0C02 JZ J110 ;TEST "JZ"
0209 D20F02 JNC J120 ;TEST "JNC"
020C CDA006 J110: CALL CPUER
020F C681 J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0
0211 FA1702 JM J130 ;TEST "JM"
0214 CDA006 CALL CPUER
0217 CA2002 J130: JZ J140 ;TEST "JZ"
021A DA2002 JC J140 ;TEST "JC"
021D E22302 JPO J150 ;TEST "JPO"
0220 CDA006 J140: CALL CPUER
0223 C6FE J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0
0225 DA2B02 JC J160 ;TEST "JC"
0228 CDA006 CALL CPUER
022B CA3402 J160: JZ J170 ;TEST "JZ"
022E E23402 JPO J170 ;TEST "JPO"
0231 FA3702 JM AIMM ;TEST "JM"
0234 CDA006 J170: CALL CPUER
;
;
;
;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS
;
0237 FE00 AIMM: CPI 0 ;A=F5H,C=0,Z=0
0239 DA4F02 JC CPIE ;TEST "CPI" FOR RE-SET CARRY
023C CA4F02 JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
023F FEF5 CPI 0F5H ;A=F5H,C=0,Z=1
0241 DA4F02 JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI")
0244 C24F02 JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO
0247 FEFF CPI 0FFH ;A=F5H,C=1,Z=0
0249 CA4F02 JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
024C DA5202 JC ACII ;TEST "CPI" FOR SET CARRY
024F CDA006 CPIE: CALL CPUER
0252 CE0A ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1
0254 CE0A ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0
0256 FE0B CPI 00BH
0258 CA5E02 JZ SUII ;TEST "ACI"
025B CDA006 CALL CPUER
025E D60C SUII: SUI 00CH ;A=FFH,C=0
0260 D60F SUI 00FH ;A=F0H,C=1
0262 FEF0 CPI 0F0H
0264 CA6A02 JZ SBII ;TEST "SUI"
0267 CDA006 CALL CPUER
026A DEF1 SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1
026C DE0E SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0
026E FEF0 CPI 0F0H
0270 CA7602 JZ ANII ;TEST "SBI"
0273 CDA006 CALL CPUER
0276 E655 ANII: ANI 055H ;A=F0H<AND>55H=50H,C=0,P=1,S=0,Z=0
0278 FE50 CPI 050H
027A CA8002 JZ ORII ;TEST "ANI"
027D CDA006 CALL CPUER
0280 F63A ORII: ORI 03AH ;A=50H<OR>3AH=7AH,C=0,P=0,S=0,Z=0
0282 FE7A CPI 07AH
0284 CA8A02 JZ XRII ;TEST "ORI"
0287 CDA006 CALL CPUER
028A EE0F XRII: XRI 00FH ;A=7AH<XOR>0FH=75H,C=0,P=0,S=0,Z=0
028C FE75 CPI 075H
028E CA9402 JZ C010 ;TEST "XRI"
0291 CDA006 CALL CPUER
;
;
;
;TEST CALLS AND RETURNS
;
0294 E600 C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1
0296 DCA006 CC CPUER ;TEST "CC"
0299 E4A006 CPO CPUER ;TEST "CPO"
029C FCA006 CM CPUER ;TEST "CM"
029F C4A006 CNZ CPUER ;TEST "CNZ"
02A2 FE00 CPI 000H
02A4 CAAA02 JZ C020 ;A=0,C=0,P=0,S=0,Z=1
02A7 CDA006 CALL CPUER
02AA D677 C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0
02AC D4A006 CNC CPUER ;TEST "CNC"
02AF ECA006 CPE CPUER ;TEST "CPE"
02B2 F4A006 CP CPUER ;TEST "CP"
02B5 CCA006 CZ CPUER ;TEST "CZ"
02B8 FE89 CPI 089H
02BA CAC002 JZ C030 ;TEST FOR "CALLS" TAKING BRANCH
02BD CDA006 CALL CPUER
02C0 E6FF C030: ANI 0FFH ;SET FLAGS BACK!
02C2 E4CD02 CPO CPOI ;TEST "CPO"
02C5 FED9 CPI 0D9H
02C7 CA2A03 JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS
02CA CDA006 CALL CPUER
02CD E8 CPOI: RPE ;TEST "RPE"
02CE C610 ADI 010H ;A=99H,C=0,P=0,S=1,Z=0
02D0 ECD902 CPE CPEI ;TEST "CPE"
02D3 C602 ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0
02D5 E0 RPO ;TEST "RPO"
02D6 CDA006 CALL CPUER
02D9 E0 CPEI: RPO ;TEST "RPO"
02DA C620 ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0
02DC FCE502 CM CMI ;TEST "CM"
02DF C604 ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0
02E1 E8 RPE ;TEST "RPE"
02E2 CDA006 CALL CPUER
02E5 F0 CMI: RP ;TEST "RP"
02E6 C680 ADI 080H ;A=39H,C=1,P=1,S=0,Z=0
02E8 F4F102 CP TCPI ;TEST "CP"
02EB C680 ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0
02ED F8 RM ;TEST "RM"
02EE CDA006 CALL CPUER
02F1 F8 TCPI: RM ;TEST "RM"
02F2 C640 ADI 040H ;A=79H,C=0,P=0,S=0,Z=0
02F4 D4FD02 CNC CNCI ;TEST "CNC"
02F7 C640 ADI 040H ;A=53H,C=0,P=1,S=0,Z=0
02F9 F0 RP ;TEST "RP"
02FA CDA006 CALL CPUER
02FD D8 CNCI: RC ;TEST "RC"
02FE C68F ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0
0300 DC0903 CC CCI ;TEST "CC"
0303 D602 SUI 002H ;A=13H,C=0,P=0,S=0,Z=0
0305 D0 RNC ;TEST "RNC"
0306 CDA006 CALL CPUER
0309 D0 CCI: RNC ;TEST "RNC"
030A C6F7 ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0
030C C41503 CNZ CNZI ;TEST "CNZ"
030F C6FE ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0
0311 D8 RC ;TEST "RC"
0312 CDA006 CALL CPUER
0315 C8 CNZI: RZ ;TEST "RZ"
0316 C601 ADI 001H ;A=00H,C=1,P=1,S=0,Z=1
0318 CC2103 CZ CZI ;TEST "CZ"
031B C6D0 ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0
031D C0 RNZ ;TEST "RNZ"
031E CDA006 CALL CPUER
0321 C0 CZI: RNZ ;TEST "RNZ"
0322 C647 ADI 047H ;A=47H,C=0,P=1,S=0,Z=0
0324 FE47 CPI 047H ;A=47H,C=0,P=1,S=0,Z=1
0326 C8 RZ ;TEST "RZ"
0327 CDA006 CALL CPUER
;
;
;
;TEST "MOV","INR",AND "DCR" INSTRUCTIONS
;
032A 3E77 MOVI: MVI A,077H
032C 3C INR A
032D 47 MOV B,A
032E 04 INR B
032F 48 MOV C,B
0330 0D DCR C
0331 51 MOV D,C
0332 5A MOV E,D
0333 63 MOV H,E
0334 6C MOV L,H
0335 7D MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A
0336 3D DCR A
0337 4F MOV C,A
0338 59 MOV E,C
0339 6B MOV L,E
033A 45 MOV B,L
033B 50 MOV D,B
033C 62 MOV H,D
033D 7C MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A
033E 57 MOV D,A
033F 14 INR D
0340 6A MOV L,D
0341 4D MOV C,L
0342 0C INR C
0343 61 MOV H,C
0344 44 MOV B,H
0345 05 DCR B
0346 58 MOV E,B
0347 7B MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A
0348 5F MOV E,A
0349 1C INR E
034A 43 MOV B,E
034B 60 MOV H,B
034C 24 INR H
034D 4C MOV C,H
034E 69 MOV L,C
034F 55 MOV D,L
0350 15 DCR D
0351 7A MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A
0352 67 MOV H,A
0353 25 DCR H
0354 54 MOV D,H
0355 42 MOV B,D
0356 68 MOV L,B
0357 2C INR L
0358 5D MOV E,L
0359 1D DCR E
035A 4B MOV C,E
035B 79 MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A
035C 6F MOV L,A
035D 2D DCR L
035E 65 MOV H,L
035F 5C MOV E,H
0360 53 MOV D,E
0361 4A MOV C,D
0362 41 MOV B,C
0363 78 MOV A,B
0364 FE77 CPI 077H
0366 C4A006 CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A
;
;
;
;TEST ARITHMETIC AND LOGIC INSTRUCTIONS
;
0369 AF XRA A
036A 0601 MVI B,001H
036C 0E03 MVI C,003H
036E 1607 MVI D,007H
0370 1E0F MVI E,00FH
0372 261F MVI H,01FH
0374 2E3F MVI L,03FH
0376 80 ADD B
0377 81 ADD C
0378 82 ADD D
0379 83 ADD E
037A 84 ADD H
037B 85 ADD L
037C 87 ADD A
037D FEF0 CPI 0F0H
037F C4A006 CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A
0382 90 SUB B
0383 91 SUB C
0384 92 SUB D
0385 93 SUB E
0386 94 SUB H
0387 95 SUB L
0388 FE78 CPI 078H
038A C4A006 CNZ CPUER ;TEST "SUB" B,C,D,E,H,L
038D 97 SUB A
038E C4A006 CNZ CPUER ;TEST "SUB" A
0391 3E80 MVI A,080H
0393 87 ADD A
0394 0601 MVI B,001H
0396 0E02 MVI C,002H
0398 1603 MVI D,003H
039A 1E04 MVI E,004H
039C 2605 MVI H,005H
039E 2E06 MVI L,006H
03A0 88 ADC B
03A1 0680 MVI B,080H
03A3 80 ADD B
03A4 80 ADD B
03A5 89 ADC C
03A6 80 ADD B
03A7 80 ADD B
03A8 8A ADC D
03A9 80 ADD B
03AA 80 ADD B
03AB 8B ADC E
03AC 80 ADD B
03AD 80 ADD B
03AE 8C ADC H
03AF 80 ADD B
03B0 80 ADD B
03B1 8D ADC L
03B2 80 ADD B
03B3 80 ADD B
03B4 8F ADC A
03B5 FE37 CPI 037H
03B7 C4A006 CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A
03BA 3E80 MVI A,080H
03BC 87 ADD A
03BD 0601 MVI B,001H
03BF 98 SBB B
03C0 06FF MVI B,0FFH
03C2 80 ADD B
03C3 99 SBB C
03C4 80 ADD B
03C5 9A SBB D
03C6 80 ADD B
03C7 9B SBB E
03C8 80 ADD B
03C9 9C SBB H
03CA 80 ADD B
03CB 9D SBB L
03CC FEE0 CPI 0E0H
03CE C4A006 CNZ CPUER ;TEST "SBB" B,C,D,E,H,L
03D1 3E80 MVI A,080H
03D3 87 ADD A
03D4 9F SBB A
03D5 FEFF CPI 0FFH
03D7 C4A006 CNZ CPUER ;TEST "SBB" A
03DA 3EFF MVI A,0FFH
03DC 06FE MVI B,0FEH
03DE 0EFC MVI C,0FCH
03E0 16EF MVI D,0EFH
03E2 1E7F MVI E,07FH
03E4 26F4 MVI H,0F4H
03E6 2EBF MVI L,0BFH
03E8 A0 ANA B ;changed from ANA A (mwd)
03E9 A1 ANA C
03EA A2 ANA D
03EB A3 ANA E
03EC A4 ANA H
03ED A5 ANA L
03EE A7 ANA A
03EF FE24 CPI 024H
03F1 C4A006 CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A
03F4 AF XRA A
03F5 0601 MVI B,001H
03F7 0E02 MVI C,002H
03F9 1604 MVI D,004H
03FB 1E08 MVI E,008H
03FD 2610 MVI H,010H
03FF 2E20 MVI L,020H
0401 B0 ORA B
0402 B1 ORA C
0403 B2 ORA D
0404 B3 ORA E
0405 B4 ORA H
0406 B5 ORA L
0407 B7 ORA A
0408 FE3F CPI 03FH
040A C4A006 CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A
040D 3E00 MVI A,000H
040F 268F MVI H,08FH
0411 2E4F MVI L,04FH
0413 A8 XRA B
0414 A9 XRA C
0415 AA XRA D
0416 AB XRA E
0417 AC XRA H
0418 AD XRA L
0419 FECF CPI 0CFH
041B C4A006 CNZ CPUER ;TEST "XRA" B,C,D,E,H,L
041E AF XRA A
041F C4A006 CNZ CPUER ;TEST "XRA" A
0422 0644 MVI B,044H
0424 0E45 MVI C,045H
0426 1646 MVI D,046H
0428 1E47 MVI E,047H
042A 2606 MVI H,(TEMP0 / 0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION
042C 2EBF MVI L,(TEMP0 AND 0FFH) ;LOW BYTE OF TEST MEMORY LOCATION
042E 70 MOV M,B
042F 0600 MVI B,000H
0431 46 MOV B,M
0432 3E44 MVI A,044H
0434 B8 CMP B
0435 C4A006 CNZ CPUER ;TEST "MOV" M,B AND B,M
0438 71 MOV M,C ;added (mwd)
0439 0E00 MVI C,000H ;added (mwd)
043B 4E MOV C,M ;added (mwd)
043C 3E45 MVI A,045H ;added (mwd)
043E B9 CMP C ;added (mwd)
043F C4A006 CNZ CPUER ;TEST "MOV" M,C AND C,M added (mwd)
0442 72 MOV M,D
0443 1600 MVI D,000H
0445 56 MOV D,M
0446 3E46 MVI A,046H
0448 BA CMP D
0449 C4A006 CNZ CPUER ;TEST "MOV" M,D AND D,M
044C 73 MOV M,E
044D 1E00 MVI E,000H
044F 5E MOV E,M
0450 3E47 MVI A,047H
0452 BB CMP E
0453 C4A006 CNZ CPUER ;TEST "MOV" M,E AND E,M
0456 74 MOV M,H
0457 2606 MVI H,(TEMP0 / 0FFH)
0459 2EBF MVI L,(TEMP0 AND 0FFH)
045B 66 MOV H,M
045C 3E06 MVI A,(TEMP0 / 0FFH)
045E BC CMP H
045F C4A006 CNZ CPUER ;TEST "MOV" M,H AND H,M
0462 75 MOV M,L
0463 2606 MVI H,(TEMP0 / 0FFH)
0465 2EBF MVI L,(TEMP0 AND 0FFH)
0467 6E MOV L,M
0468 3EBF MVI A,(TEMP0 AND 0FFH)
046A BD CMP L
046B C4A006 CNZ CPUER ;TEST "MOV" M,L AND L,M
046E 2606 MVI H,(TEMP0 / 0FFH)
0470 2EBF MVI L,(TEMP0 AND 0FFH)
0472 3E32 MVI A,032H
0474 77 MOV M,A
0475 BE CMP M
0476 C4A006 CNZ CPUER ;TEST "MOV" M,A
0479 86 ADD M
047A FE64 CPI 064H
047C C4A006 CNZ CPUER ;TEST "ADD" M
047F AF XRA A
0480 7E MOV A,M
0481 FE32 CPI 032H
0483 C4A006 CNZ CPUER ;TEST "MOV" A,M
0486 2606 MVI H,(TEMP0 / 0FFH)
0488 2EBF MVI L,(TEMP0 AND 0FFH)
048A 7E MOV A,M
048B 96 SUB M
048C C4A006 CNZ CPUER ;TEST "SUB" M
048F 3E80 MVI A,080H
0491 87 ADD A
0492 8E ADC M
0493 FE33 CPI 033H
0495 C4A006 CNZ CPUER ;TEST "ADC" M
0498 3E80 MVI A,080H
049A 87 ADD A
049B 9E SBB M
049C FECD CPI 0CDH
049E C4A006 CNZ CPUER ;TEST "SBB" M
04A1 A6 ANA M
04A2 C4A006 CNZ CPUER ;TEST "ANA" M
04A5 3E25 MVI A,025H
04A7 B6 ORA M
04A8 FE37 CPI 037H
04AA C4A006 CNZ CPUER ;TEST "ORA" M
04AD AE XRA M
04AE FE05 CPI 005H
04B0 C4A006 CNZ CPUER ;TEST "XRA" M
04B3 3655 MVI M,055H
04B5 34 INR M
04B6 35 DCR M
04B7 86 ADD M
04B8 FE5A CPI 05AH
04BA C4A006 CNZ CPUER ;TEST "INR","DCR",AND "MVI" M
04BD 01FF12 LXI B,12FFH
04C0 11FF12 LXI D,12FFH
04C3 21FF12 LXI H,12FFH
04C6 03 INX B
04C7 13 INX D
04C8 23 INX H
04C9 3E13 MVI A,013H
04CB B8 CMP B
04CC C4A006 CNZ CPUER ;TEST "LXI" AND "INX" B
04CF BA CMP D
04D0 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" D
04D3 BC CMP H
04D4 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" H
04D7 3E00 MVI A,000H
04D9 B9 CMP C
04DA C4A006 CNZ CPUER ;TEST "LXI" AND "INX" B
04DD BB CMP E
04DE C4A006 CNZ CPUER ;TEST "LXI" AND "INX" D
04E1 BD CMP L
04E2 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" H
04E5 0B DCX B
04E6 1B DCX D
04E7 2B DCX H
04E8 3E12 MVI A,012H
04EA B8 CMP B
04EB C4A006 CNZ CPUER ;TEST "DCX" B
04EE BA CMP D
04EF C4A006 CNZ CPUER ;TEST "DCX" D
04F2 BC CMP H
04F3 C4A006 CNZ CPUER ;TEST "DCX" H
04F6 3EFF MVI A,0FFH
04F8 B9 CMP C
04F9 C4A006 CNZ CPUER ;TEST "DCX" B
04FC BB CMP E
04FD C4A006 CNZ CPUER ;TEST "DCX" D
0500 BD CMP L
0501 C4A006 CNZ CPUER ;TEST "DCX" H
0504 32BF06 STA TEMP0
0507 AF XRA A
0508 3ABF06 LDA TEMP0
050B FEFF CPI 0FFH
050D C4A006 CNZ CPUER ;TEST "LDA" AND "STA"
0510 2ABD06 LHLD TEMPP
0513 22BF06 SHLD TEMP0
0516 3ABD06 LDA TEMPP
0519 47 MOV B,A
051A 3ABF06 LDA TEMP0
051D B8 CMP B
051E C4A006 CNZ CPUER ;TEST "LHLD" AND "SHLD"
0521 3ABE06 LDA TEMPP+1
0524 47 MOV B,A
0525 3AC006 LDA TEMP0+1
0528 B8 CMP B
0529 C4A006 CNZ CPUER ;TEST "LHLD" AND "SHLD"
052C 3EAA MVI A,0AAH
052E 32BF06 STA TEMP0
0531 44 MOV B,H
0532 4D MOV C,L
0533 AF XRA A
0534 0A LDAX B
0535 FEAA CPI 0AAH
0537 C4A006 CNZ CPUER ;TEST "LDAX" B
053A 3C INR A
053B 02 STAX B
053C 3ABF06 LDA TEMP0
053F FEAB CPI 0ABH
0541 C4A006 CNZ CPUER ;TEST "STAX" B
0544 3E77 MVI A,077H
0546 32BF06 STA TEMP0
0549 2ABD06 LHLD TEMPP
054C 110000 LXI D,00000H
054F EB XCHG
0550 AF XRA A
0551 1A LDAX D
0552 FE77 CPI 077H
0554 C4A006 CNZ CPUER ;TEST "LDAX" D AND "XCHG"
0557 AF XRA A
0558 84 ADD H
0559 85 ADD L
055A C4A006 CNZ CPUER ;TEST "XCHG"
055D 3ECC MVI A,0CCH
055F 12 STAX D
0560 3ABF06 LDA TEMP0
0563 FECC CPI 0CCH
0565 12 STAX D
0566 3ABF06 LDA TEMP0
0569 FECC CPI 0CCH
056B C4A006 CNZ CPUER ;TEST "STAX" D
056E 217777 LXI H,07777H
0571 29 DAD H
0572 3EEE MVI A,0EEH
0574 BC CMP H
0575 C4A006 CNZ CPUER ;TEST "DAD" H
0578 BD CMP L
0579 C4A006 CNZ CPUER ;TEST "DAD" H
057C 215555 LXI H,05555H
057F 01FFFF LXI B,0FFFFH
0582 09 DAD B
0583 3E55 MVI A,055H
0585 D4A006 CNC CPUER ;TEST "DAD" B
0588 BC CMP H
0589 C4A006 CNZ CPUER ;TEST "DAD" B
058C 3E54 MVI A,054H
058E BD CMP L
058F C4A006 CNZ CPUER ;TEST "DAD" B
0592 21AAAA LXI H,0AAAAH
0595 113333 LXI D,03333H
0598 19 DAD D
0599 3EDD MVI A,0DDH
059B BC CMP H
059C C4A006 CNZ CPUER ;TEST "DAD" D
059F BD CMP L
05A0 C4A006 CNZ CPUER ;TEST "DAD" B
05A3 37 STC
05A4 D4A006 CNC CPUER ;TEST "STC"
05A7 3F CMC
05A8 DCA006 CC CPUER ;TEST "CMC
05AB 3EAA MVI A,0AAH
05AD 2F CMA
05AE FE55 CPI 055H
05B0 C4A006 CNZ CPUER ;TEST "CMA"
05B3 B7 ORA A ;RE-SET AUXILIARY CARRY
05B4 27 DAA
05B5 FE55 CPI 055H
05B7 C4A006 CNZ CPUER ;TEST "DAA"
05BA 3E88 MVI A,088H
05BC 87 ADD A
05BD 27 DAA
05BE FE76 CPI 076H
05C0 C4A006 CNZ CPUER ;TEST "DAA"
05C3 AF XRA A
05C4 3EAA MVI A,0AAH
05C6 27 DAA
05C7 D4A006 CNC CPUER ;TEST "DAA"
05CA FE10 CPI 010H
05CC C4A006 CNZ CPUER ;TEST "DAA"
05CF AF XRA A
05D0 3E9A MVI A,09AH
05D2 27 DAA
05D3 D4A006 CNC CPUER ;TEST "DAA"
05D6 C4A006 CNZ CPUER ;TEST "DAA"
05D9 37 STC
05DA 3E42 MVI A,042H
05DC 07 RLC
05DD DCA006 CC CPUER ;TEST "RLC" FOR RE-SET CARRY
05E0 07 RLC
05E1 D4A006 CNC CPUER ;TEST "RLC" FOR SET CARRY
05E4 FE09 CPI 009H
05E6 C4A006 CNZ CPUER ;TEST "RLC" FOR ROTATION
05E9 0F RRC
05EA D4A006 CNC CPUER ;TEST "RRC" FOR SET CARRY
05ED 0F RRC
05EE FE42 CPI 042H
05F0 C4A006 CNZ CPUER ;TEST "RRC" FOR ROTATION
05F3 17 RAL
05F4 17 RAL
05F5 D4A006 CNC CPUER ;TEST "RAL" FOR SET CARRY
05F8 FE08 CPI 008H
05FA C4A006 CNZ CPUER ;TEST "RAL" FOR ROTATION
05FD 1F RAR
05FE 1F RAR
05FF DCA006 CC CPUER ;TEST "RAR" FOR RE-SET CARRY
0602 FE02 CPI 002H
0604 C4A006 CNZ CPUER ;TEST "RAR" FOR ROTATION
0607 013412 LXI B,01234H
060A 11AAAA LXI D,0AAAAH
060D 215555 LXI H,05555H
0610 AF XRA A
0611 C5 PUSH B
0612 D5 PUSH D
0613 E5 PUSH H
0614 F5 PUSH PSW
0615 010000 LXI B,00000H
0618 110000 LXI D,00000H
061B 210000 LXI H,00000H
061E 3EC0 MVI A,0C0H
0620 C6F0 ADI 0F0H
0622 F1 POP PSW
0623 E1 POP H
0624 D1 POP D
0625 C1 POP B
0626 DCA006 CC CPUER ;TEST "PUSH PSW" AND "POP PSW"
0629 C4A006 CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW"
062C E4A006 CPO CPUER ;TEST "PUSH PSW" AND "POP PSW"
062F FCA006 CM CPUER ;TEST "PUSH PSW" AND "POP PSW"
0632 3E12 MVI A,012H
0634 B8 CMP B
0635 C4A006 CNZ CPUER ;TEST "PUSH B" AND "POP B"
0638 3E34 MVI A,034H
063A B9 CMP C
063B C4A006 CNZ CPUER ;TEST "PUSH B" AND "POP B"
063E 3EAA MVI A,0AAH
0640 BA CMP D
0641 C4A006 CNZ CPUER ;TEST "PUSH D" AND "POP D"
0644 BB CMP E
0645 C4A006 CNZ CPUER ;TEST "PUSH D" AND "POP D"
0648 3E55 MVI A,055H
064A BC CMP H
064B C4A006 CNZ CPUER ;TEST "PUSH H" AND "POP H"
064E BD CMP L
064F C4A006 CNZ CPUER ;TEST "PUSH H" AND "POP H"
0652 210000 LXI H,00000H
0655 39 DAD SP
0656 22C406 SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER!
0659 31C306 LXI SP,TEMP4
065C 3B DCX SP
065D 3B DCX SP
065E 33 INX SP
065F 3B DCX SP
0660 3E55 MVI A,055H
0662 32C106 STA TEMP2
0665 2F CMA
0666 32C206 STA TEMP3
0669 C1 POP B
066A B8 CMP B
066B C4A006 CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP
066E 2F CMA
066F B9 CMP C
0670 C4A006 CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP
0673 21C306 LXI H,TEMP4
0676 F9 SPHL
0677 213377 LXI H,07733H
067A 3B DCX SP
067B 3B DCX SP
067C E3 XTHL
067D 3AC206 LDA TEMP3
0680 FE77 CPI 077H
0682 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL"
0685 3AC106 LDA TEMP2
0688 FE33 CPI 033H
068A C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL"
068D 3E55 MVI A,055H
068F BD CMP L
0690 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL"
0693 2F CMA
0694 BC CMP H
0695 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL"
0698 2AC406 LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER
069B F9 SPHL
069C 21B406 LXI H,CPUOK
069F E9 PCHL ;TEST "PCHL"
;
;
;
06A0 219001 CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE
06A3 CD4B01 CALL MSG
06A6 E1 POP H ;HL = ADDRESS FOLLOWING CALL CPUER
06A7 E5 PUSH H
06A8 7C MOV A,H
06A9 CD5A01 CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE
06AC E1 POP H
06AD 7D MOV A,L
06AE CD5A01 CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE
06B1 C30000 JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
06B4 217A01 CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE
06B7 CD4B01 CALL MSG
06BA C30000 JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
06BD BF06 TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD",
; AND "LDAX" INSTRUCTIONS
;
06BF TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
06C0 TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
06C1 TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
06C2 TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
06C3 TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
06C4 SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION
;
;
;
07BD = STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA
;
;
;
06C6 END

View File

@@ -6,6 +6,8 @@
namespace Intel8080
{
using EightBit;
using System;
using System.Diagnostics;
public class Intel8080(Bus bus, InputOutput ports) : IntelProcessor(bus)
{
@@ -63,17 +65,62 @@ namespace Intel8080
}
}
private void MemoryUpdate(int ticks)
{
Debug.Assert(ticks > 0, "Ticks must be greater than zero");
this.OnWritingMemory();
this.Tick(ticks + 1);
base.MemoryWrite();
this.Tick();
this.OnWrittenMemory();
}
protected override void MemoryWrite()
{
this.MemoryUpdate(1);
}
protected override byte MemoryRead()
{
this.OnReadingMemory();
this.Tick(2);
base.MemoryRead();
this.OnReadMemory();
this.Tick(2);
return this.Bus.Data;
}
protected override void HandleRESET()
{
base.HandleRESET();
this.Tick(3);
this.DisableInterrupts();
this.SP.Word = this.AF.Word = (ushort)Mask.Sixteen;
}
private byte ReadDataUnderInterrupt()
{
this.Tick(4);
return this.Bus.Data;
}
protected override void Call(Register16 destination)
{
this.Tick();
base.Call(destination);
}
protected override void JumpRelative(sbyte offset)
{
base.JumpRelative(offset);
this.Tick(5);
}
protected override void HandleINT()
{
base.HandleINT();
this.Execute(this.Bus.Data);
this.Tick(3);
var data = this.ReadDataUnderInterrupt();
this.Tick();
this.Execute(data);
}
private int Zero() => ZeroTest(this.F);
@@ -132,52 +179,53 @@ namespace Intel8080
protected override void EnableInterrupts() => this.interruptEnable = true;
private byte R(int r) => r switch
{
0 => this.B,
1 => this.C,
2 => this.D,
3 => this.E,
4 => this.H,
5 => this.L,
6 => this.MemoryRead(this.HL),
7 => this.A,
_ => throw new ArgumentOutOfRangeException(nameof(r)),
};
private void R(int r, byte value)
private ref byte R(int r, AccessLevel access = AccessLevel.ReadOnly)
{
switch (r)
{
case 0:
this.B = value;
break;
return ref this.B;
case 1:
this.C = value;
break;
return ref this.C;
case 2:
this.D = value;
break;
return ref this.D;
case 3:
this.E = value;
break;
return ref this.E;
case 4:
this.H = value;
break;
return ref this.H;
case 5:
this.L = value;
break;
return ref this.L;
case 6:
this.MemoryWrite(this.HL, value);
break;
this.Bus.Address.Assign(this.HL);
switch (access)
{
case AccessLevel.ReadOnly:
this.MemoryRead();
break;
case AccessLevel.WriteOnly:
break;
default:
throw new NotSupportedException("Invalid access level");
}
// Will need a post-MemoryWrite
return ref this.Bus.Data;
case 7:
this.A = value;
break;
return ref this.A;
default:
throw new ArgumentOutOfRangeException(nameof(r));
}
}
private void R(int r, byte value, int ticks = 1)
{
this.R(r, AccessLevel.WriteOnly) = value;
if (r == 6)
{
this.MemoryUpdate(ticks);
}
}
private Register16 RP(int rp) => rp switch
{
0 => this.BC,
@@ -198,6 +246,8 @@ namespace Intel8080
private void Execute(int x, int y, int z, int p, int q)
{
var memoryY = y == 6;
var memoryZ = z == 6;
switch (x)
{
case 0:
@@ -207,7 +257,6 @@ namespace Intel8080
switch (y)
{
case 0: // NOP
this.Tick(4);
break;
default:
break;
@@ -219,11 +268,10 @@ namespace Intel8080
{
case 0: // LD rp,nn
this.RP(p).Assign(this.FetchWord());
this.Tick(10);
break;
case 1: // ADD HL,rp
this.Add(this.RP(p));
this.Tick(11);
this.Tick(7);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -238,21 +286,17 @@ namespace Intel8080
{
case 0: // LD (BC),A
this.WriteMemoryIndirect(this.BC, this.A);
this.Tick(7);
break;
case 1: // LD (DE),A
this.WriteMemoryIndirect(this.DE, this.A);
this.Tick(7);
break;
case 2: // LD (nn),HL
this.FetchWordAddress();
this.SetWord(this.HL);
this.Tick(16);
break;
case 3: // LD (nn),A
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.WriteMemoryIndirect(this.A);
this.Tick(13);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -264,21 +308,17 @@ namespace Intel8080
{
case 0: // LD A,(BC)
this.A = this.ReadMemoryIndirect(this.BC);
this.Tick(7);
break;
case 1: // LD A,(DE)
this.A = this.ReadMemoryIndirect(this.DE);
this.Tick(7);
break;
case 2: // LD HL,(nn)
this.FetchWordAddress();
this.HL.Assign(this.GetWord());
this.Tick(16);
this.GetInto(this.HL);
break;
case 3: // LD A,(nn)
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.A = this.ReadMemoryIndirect();
this.Tick(13);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -291,41 +331,31 @@ namespace Intel8080
break;
case 3: // 16-bit INC/DEC
switch (q)
_ = q switch
{
case 0: // INC rp
_ = this.RP(p).Increment();
break;
case 1: // DEC rp
_ = this.RP(p).Decrement();
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(6);
// INC rp
0 => this.RP(p).Increment(),
// DEC rp
1 => this.RP(p).Decrement(),
_ => throw new NotSupportedException("Invalid operation mode"),
};
this.Tick(2);
break;
case 4: // 8-bit INC
this.R(y, this.Increment(this.R(y)));
this.Tick(4);
this.R(y, this.Increment(this.R(y)), 2);
break;
case 5: // 8-bit DEC
this.R(y, this.Decrement(this.R(y)));
this.Tick(4);
if (y == 6)
{
this.Tick(7);
}
this.R(y, this.Decrement(this.R(y)), 2);
break;
case 6: // 8-bit load immediate
this.R(y, this.FetchByte());
this.Tick(7);
if (y == 6)
{
this.Tick(3);
_ = this.FetchByte(); // LD r,n
if (memoryY)
{
this.Tick(2);
}
this.R(y, this.Bus.Data);
}
break;
case 7: // Assorted operations on accumulator/flags
switch (y)
@@ -357,8 +387,6 @@ namespace Intel8080
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(4);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -366,20 +394,14 @@ namespace Intel8080
break;
case 1: // 8-bit loading
if (z == 6 && y == 6)
if (memoryZ && memoryY)
{
this.LowerHALT(); // Exception (replaces LD (HL), (HL))
}
else
{
this.R(y, this.R(z));
if (y == 6 || z == 6)
{
this.Tick(3); // M operations
}
}
this.Tick(4);
break;
case 2: // Operate on accumulator and register/memory location
switch (y)
@@ -411,46 +433,31 @@ namespace Intel8080
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(4);
if (z == 6)
{
this.Tick(3);
}
break;
case 3:
switch (z)
{
case 0: // Conditional return
if (this.ReturnConditionalFlag(y))
{
this.Tick(6);
}
this.Tick(5);
this.ReturnConditionalFlag(y);
break;
case 1: // POP & various ops
switch (q)
{
case 0: // POP rp2[p]
this.RP2(p).Assign(this.PopWord());
this.Tick(10);
this.PopInto(this.RP2(p));
break;
case 1:
switch (p)
{
case 0: // RET
this.Return();
this.Tick(10);
break;
case 2: // JP HL
this.Jump(this.HL);
this.Tick(4);
break;
case 3: // LD SP,HL
this.SP.Assign(this.HL);
this.Tick(4);
this.Tick(2);
break;
default:
break;
@@ -463,39 +470,32 @@ namespace Intel8080
break;
case 2: // Conditional jump
_ = this.JumpConditionalFlag(y);
this.Tick(10);
this.JumpConditionalFlag(y);
break;
case 3: // Assorted operations
switch (y)
{
case 0: // JP nn
this.JumpIndirect();
this.Tick(10);
break;
case 2: // OUT (n),A
this.WritePort(this.FetchByte());
this.Tick(11);
break;
case 3: // IN A,(n)
this.A = this.ReadPort(this.FetchByte());
this.Tick(11);
break;
case 4: // EX (SP),HL
this.XHTL(this.HL);
this.Tick(19);
break;
case 5: // EX DE,HL
(this.DE.Word, this.HL.Word) = (this.HL.Word, this.DE.Word);
this.Tick(4);
(this.HL.Low, this.DE.Low) = (this.DE.Low, this.HL.Low);
(this.HL.High, this.DE.High) = (this.DE.High, this.HL.High);
break;
case 6: // DI
this.DisableInterrupts();
this.Tick(4);
break;
case 7: // EI
this.EnableInterrupts();
this.Tick(4);
break;
default:
break;
@@ -503,26 +503,20 @@ namespace Intel8080
break;
case 4: // Conditional call: CALL cc[y], nn
if (this.CallConditionalFlag(y))
{
this.Tick(7);
}
this.Tick(10);
this.CallConditionalFlag(y);
break;
case 5: // PUSH & various ops
switch (q)
{
case 0: // PUSH rp2[p]
this.Tick();
this.PushWord(this.RP2(p));
this.Tick(11);
break;
case 1:
switch (p)
{
case 0: // CALL nn
this.CallIndirect();
this.Tick(17);
break;
default:
break;
@@ -535,41 +529,39 @@ namespace Intel8080
break;
case 6: // Operate on accumulator and immediate operand: alu[y] n
_ = this.FetchByte();
switch (y)
{
case 0: // ADD A,n
this.Add(this.FetchByte());
this.Add(this.Bus.Data);
break;
case 1: // ADC A,n
this.ADC(this.FetchByte());
this.ADC(this.Bus.Data);
break;
case 2: // SUB n
this.SUB(this.FetchByte());
this.SUB(this.Bus.Data);
break;
case 3: // SBC A,n
this.SBB(this.FetchByte());
this.SBB(this.Bus.Data);
break;
case 4: // AND n
this.AndR(this.FetchByte());
this.AndR(this.Bus.Data);
break;
case 5: // XOR n
this.XorR(this.FetchByte());
this.XorR(this.Bus.Data);
break;
case 6: // OR n
this.OrR(this.FetchByte());
this.OrR(this.Bus.Data);
break;
case 7: // CP n
this.Compare(this.FetchByte());
this.Compare(this.Bus.Data);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(7);
break;
case 7: // Restart: RST y * 8
this.Restart((byte)(y << 3));
this.Tick(11);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -608,6 +600,16 @@ namespace Intel8080
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
protected sealed override void ReturnConditionalFlag(int flag)
{
var condition = this.ConvertCondition(flag);
this.Tick();
if (condition)
{
this.Return();
}
}
private void Add(Register16 value)
{
var result = this.HL.Word + value.Word;
@@ -725,13 +727,16 @@ namespace Intel8080
private void XHTL(Register16 exchange)
{
this.MEMPTR.Low = this.MemoryRead(this.SP);
_ = this.Bus.Address.Increment();
this.Bus.Address.Increment();
this.MEMPTR.High = this.MemoryRead();
this.MemoryWrite(exchange.High);
this.Bus.Data = exchange.High;
exchange.High = this.MEMPTR.High;
this.MemoryUpdate(2);
_ = this.Bus.Address.Decrement();
this.MemoryWrite(exchange.Low);
this.Bus.Data = exchange.Low;
exchange.Low = this.MEMPTR.Low;
this.MemoryUpdate(1);
this.Tick(2);
}
private byte ReadMemoryIndirect(Register16 via)
@@ -768,7 +773,12 @@ namespace Intel8080
this.WritePort();
}
private void WritePort() => this.ports.Write(this.Bus.Address, this.Bus.Data);
private void WritePort()
{
this.Tick(3);
this.ports.Write(this.Bus.Address, this.Bus.Data);
this.Tick(1);
}
private byte ReadPort(byte port)
{
@@ -776,6 +786,12 @@ namespace Intel8080
return this.ReadPort();
}
private byte ReadPort() => this.Bus.Data = this.ports.Read(this.Bus.Address);
private byte ReadPort()
{
this.Tick(2);
this.Bus.Data = this.ports.Read(this.Bus.Address);
this.Tick(2);
return this.Bus.Data;
}
}
}

View File

@@ -6,7 +6,7 @@ namespace LR35902.BlarggTest
{
using System;
internal class Board : Bus
internal sealed class Board : Bus
{
private readonly Configuration configuration;
private readonly Disassembler disassembler;

View File

@@ -4,7 +4,7 @@
namespace LR35902.BlarggTest
{
internal class Computer(Configuration configuration)
internal sealed class Computer(Configuration configuration)
{
private readonly Board board = new(configuration);

View File

@@ -4,7 +4,7 @@
namespace LR35902.BlarggTest
{
internal class Configuration
internal sealed class Configuration
{
public bool DebugMode { get; set; }

View File

@@ -6,17 +6,11 @@ namespace LR35902.FuseTest
{
using Fuse;
public class TestSuite<T>
public class TestSuite<T>(string path)
where T : IRegisterState, new()
{
private readonly Tests<T> tests;
private readonly Results<T> results;
public TestSuite(string path)
{
this.tests = new Tests<T>(path + ".in");
this.results = new Results<T>(path + ".expected");
}
private readonly Tests<T> tests = new(path + ".in");
private readonly Results<T> results = new(path + ".expected");
public void Read()
{

View File

@@ -369,19 +369,19 @@ namespace LR35902
this.TickMachine();
}
protected override bool JumpConditional(bool condition)
protected override void JumpConditional(bool condition)
{
if (base.JumpConditional(condition))
base.JumpConditional(condition);
if (condition)
{
this.TickMachine();
}
return condition;
}
protected override bool ReturnConditional(bool condition)
protected override void ReturnConditional(bool condition)
{
this.TickMachine();
return base.ReturnConditional(condition);
base.ReturnConditional(condition);
}
protected override void Return()
@@ -528,7 +528,7 @@ namespace LR35902
case 5:
case 6:
case 7:
_ = this.JumpRelativeConditionalFlag(y - 4);
this.JumpRelativeConditionalFlag(y - 4);
break;
default:
throw new InvalidOperationException("Unreachable code block reached");
@@ -727,7 +727,7 @@ namespace LR35902
case 1:
case 2:
case 3:
_ = this.ReturnConditionalFlag(y);
this.ReturnConditionalFlag(y);
break;
case 4: // GB: LD (FF00 + n),A
@@ -775,7 +775,7 @@ namespace LR35902
switch (q)
{
case 0: // POP rp2[p]
this.RP2(p).Assign(this.PopWord());
this.PopInto(this.RP2(p));
break;
case 1:
switch (p)
@@ -811,20 +811,20 @@ namespace LR35902
case 1:
case 2:
case 3:
_ = this.JumpConditionalFlag(y);
this.JumpConditionalFlag(y);
break;
case 4: // GB: LD (FF00 + C),A
this.MemoryWrite(this.C, IoRegisters.BasePage, this.A);
break;
case 5: // GB: LD (nn),A
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.MemoryWrite(this.MEMPTR, this.A);
break;
case 6: // GB: LD A,(FF00 + C)
this.A = this.MemoryRead(this.C, IoRegisters.BasePage);
break;
case 7: // GB: LD A,(nn)
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.A = this.MemoryRead(this.MEMPTR);
break;
default:
@@ -855,7 +855,7 @@ namespace LR35902
break;
case 4: // Conditional call: CALL cc[y], nn
_ = this.CallConditionalFlag(y);
this.CallConditionalFlag(y);
break;
case 5: // PUSH & various ops
@@ -884,31 +884,32 @@ namespace LR35902
break;
case 6: // Operate on accumulator and immediate operand: alu[y] n
_ = this.FetchByte();
switch (y)
{
case 0: // ADD A,n
this.A = this.Add(this.A, this.FetchByte());
this.A = this.Add(this.A, this.Bus.Data);
break;
case 1: // ADC A,n
this.A = this.ADC(this.A, this.FetchByte());
this.A = this.ADC(this.A, this.Bus.Data);
break;
case 2: // SUB n
this.A = this.Subtract(this.A, this.FetchByte());
this.A = this.Subtract(this.A, this.Bus.Data);
break;
case 3: // SBC A,n
this.A = this.SBC(this.A, this.FetchByte());
this.A = this.SBC(this.A, this.Bus.Data);
break;
case 4: // AND n
this.AndR(this.FetchByte());
this.AndR(this.Bus.Data);
break;
case 5: // XOR n
this.XorR(this.FetchByte());
this.XorR(this.Bus.Data);
break;
case 6: // OR n
this.OrR(this.FetchByte());
this.OrR(this.Bus.Data);
break;
case 7: // CP n
this.Compare(this.FetchByte());
this.Compare(this.Bus.Data);
break;
default:
throw new InvalidOperationException("Invalid operation mode");

View File

@@ -308,11 +308,11 @@ namespace M6502
#region Cycle wastage
protected void SwallowRead() => this.MemoryRead(this.PC);
protected void SwallowRead() => _ = this.MemoryRead(this.PC);
protected void SwallowPop() => this.MemoryRead(this.S, 1);
protected void SwallowPop() => _ = this.MemoryRead(this.S, 1);
protected void SwallowFetch() => this.FetchByte();
protected void SwallowFetch() => _ = this.FetchByte();
#endregion
@@ -326,17 +326,17 @@ namespace M6502
switch (this.OpCode)
{
case 0x00: this.SwallowFetch(); this.Interrupt(IRQ_vector, InterruptSource.software); break;// BRK (implied)
case 0x01: this.IndexedIndirectXRead(); this.OrR(); break; // ORA (indexed indirect X)
case 0x01: this.OrR(this.IndexedIndirectXRead()); break; // ORA (indexed indirect X)
case 0x05: this.ZeroPageRead(); this.OrR(); break; // ORA (zero page)
case 0x06: this.ZeroPageRead(); this.ModifyWrite(this.ASL()); break; // ASL (zero page)
case 0x08: this.SwallowRead(); this.PHP(); break; // PHP (implied)
case 0x09: this.FetchByte(); this.OrR(); break; // ORA (immediate)
case 0x09: this.OrR(this.FetchByte()); break; // ORA (immediate)
case 0x0a: this.SwallowRead(); this.A = this.ASL(this.A); break; // ASL A (implied)
case 0x0d: this.AbsoluteRead(); this.OrR(); break; // ORA (absolute)
case 0x0e: this.AbsoluteRead(); this.ModifyWrite(this.ASL()); break; // ASL (absolute)
case 0x10: this.BranchNot(this.Negative); break; // BPL (relative)
case 0x11: this.IndirectIndexedYRead(); this.OrR(); break; // ORA (indirect indexed Y)
case 0x11: this.OrR(this.IndirectIndexedYRead()); break; // ORA (indirect indexed Y)
case 0x15: this.ZeroPageXRead(); this.OrR(); break; // ORA (zero page, X)
case 0x16: this.ZeroPageXRead(); this.ModifyWrite(this.ASL()); break; // ASL (zero page, X)
case 0x18: this.SwallowRead(); this.ResetFlag(StatusBits.CF); break; // CLC (implied)
@@ -345,19 +345,19 @@ namespace M6502
case 0x1e: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.ASL()); break; // ASL (absolute, X)
case 0x20: this.JSR(); break; // JSR (absolute)
case 0x21: this.IndexedIndirectXRead(); this.AndR(); break; // AND (indexed indirect X)
case 0x21: this.AndR(this.IndexedIndirectXRead()); break; // AND (indexed indirect X)
case 0x24: this.ZeroPageRead(); this.BIT(); break; // BIT (zero page)
case 0x25: this.ZeroPageRead(); this.AndR(); break; // AND (zero page)
case 0x26: this.ZeroPageRead(); this.ModifyWrite(this.ROL()); break; // ROL (zero page)
case 0x28: this.SwallowRead(); this.PLP(); break; // PLP (implied)
case 0x29: this.FetchByte(); this.AndR(); break; // AND (immediate)
case 0x29: this.AndR(this.FetchByte()); break; // AND (immediate)
case 0x2a: this.SwallowRead(); this.A = this.ROL(this.A); break; // ROL A (implied)
case 0x2c: this.AbsoluteRead(); this.BIT(); break; // BIT (absolute)
case 0x2d: this.AbsoluteRead(); this.AndR(); break; // AND (absolute)
case 0x2e: this.AbsoluteRead(); this.ModifyWrite(this.ROL()); break; // ROL (absolute)
case 0x30: this.Branch(this.Negative); break; // BMI (relative)
case 0x31: this.IndirectIndexedYRead(); this.AndR(); break; // AND (indirect indexed Y)
case 0x31: this.AndR(this.IndirectIndexedYRead()); break; // AND (indirect indexed Y)
case 0x35: this.ZeroPageXRead(); this.AndR(); break; // AND (zero page, X)
case 0x36: this.ZeroPageXRead(); this.ModifyWrite(this.ROL()); break; // ROL (zero page, X)
case 0x38: this.SwallowRead(); this.SetFlag(StatusBits.CF); break; // SEC (implied)
@@ -366,19 +366,19 @@ namespace M6502
case 0x3e: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.ROL()); break; // ROL (absolute, X)
case 0x40: this.SwallowRead(); this.RTI(); break; // RTI (implied)
case 0x41: this.IndexedIndirectXRead(); this.EorR(); break; // EOR (indexed indirect X)
case 0x41: this.EorR(this.IndexedIndirectXRead()); break; // EOR (indexed indirect X)
case 0x44: this.ZeroPageRead(); break; // *NOP (zero page)
case 0x45: this.ZeroPageRead(); this.EorR(); break; // EOR (zero page)
case 0x46: this.ZeroPageRead(); this.ModifyWrite(this.LSR()); break; // LSR (zero page)
case 0x48: this.SwallowRead(); this.Push(this.A); break; // PHA (implied)
case 0x49: this.FetchByte(); this.EorR(); break; // EOR (immediate)
case 0x49: this.EorR(this.FetchByte()); break; // EOR (immediate)
case 0x4a: this.SwallowRead(); this.A = this.LSR(this.A); break; // LSR A (implied)
case 0x4c: this.AbsoluteAddress(); this.Jump(this.Bus.Address); break; // JMP (absolute)
case 0x4d: this.AbsoluteRead(); this.EorR(); break; // EOR (absolute)
case 0x4e: this.AbsoluteRead(); this.ModifyWrite(this.LSR()); break; // LSR (absolute)
case 0x50: this.BranchNot(this.Overflow); break; // BVC (relative)
case 0x51: this.IndirectIndexedYRead(); this.EorR(); break; // EOR (indirect indexed Y)
case 0x51: this.EorR(this.IndirectIndexedYRead()); break; // EOR (indirect indexed Y)
case 0x54: this.ZeroPageXRead(); break; // *NOP (zero page, X)
case 0x55: this.ZeroPageXRead(); this.EorR(); break; // EOR (zero page, X)
case 0x56: this.ZeroPageXRead(); this.ModifyWrite(this.LSR()); break; // LSR (zero page, X)
@@ -388,27 +388,27 @@ namespace M6502
case 0x5e: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.LSR()); break; // LSR (absolute, X)
case 0x60: this.SwallowRead(); this.Return(); break; // RTS (implied)
case 0x61: this.IndexedIndirectXRead(); this.ADC(); break; // ADC (indexed indirect X)
case 0x65: this.ZeroPageRead(); this.ADC(); break; // ADC (zero page)
case 0x61: this.ADC(this.IndexedIndirectXRead()); break; // ADC (indexed indirect X)
case 0x65: this.ADC(this.ZeroPageRead()); break; // ADC (zero page)
case 0x66: this.ZeroPageRead(); this.ModifyWrite(this.ROR()); break; // ROR (zero page)
case 0x68: this.SwallowRead(); this.SwallowPop(); this.A = this.Through(this.Pop()); break; // PLA (implied)
case 0x69: this.FetchByte(); this.ADC(); break; // ADC (immediate)
case 0x69: this.ADC(this.FetchByte()); break; // ADC (immediate)
case 0x6a: this.SwallowRead(); this.A = this.ROR(this.A); break; // ROR A (implied)
case 0x6c: this.IndirectAddress(); this.Jump(this.Bus.Address); break; // JMP (indirect)
case 0x6d: this.AbsoluteRead(); this.ADC(); break; // ADC (absolute)
case 0x6d: this.ADC(this.AbsoluteRead()); break; // ADC (absolute)
case 0x6e: this.AbsoluteRead(); this.ModifyWrite(this.ROR()); break; // ROR (absolute)
case 0x70: this.Branch(this.Overflow); break; // BVS (relative)
case 0x71: this.IndirectIndexedYRead(); this.ADC(); break; // ADC (indirect indexed Y)
case 0x75: this.ZeroPageXRead(); this.ADC(); break; // ADC (zero page, X)
case 0x71: this.ADC(this.IndirectIndexedYRead()); break; // ADC (indirect indexed Y)
case 0x75: this.ADC(this.ZeroPageXRead()); break; // ADC (zero page, X)
case 0x76: this.ZeroPageXRead(); this.ModifyWrite(this.ROR()); break; // ROR (zero page, X)
case 0x78: this.SwallowRead(); this.SetFlag(StatusBits.IF); break; // SEI (implied)
case 0x79: this.AbsoluteYRead(); this.ADC(); break; // ADC (absolute, Y)
case 0x7d: this.AbsoluteXRead(); this.ADC(); break; // ADC (absolute, X)
case 0x79: this.ADC(this.AbsoluteYRead()); break; // ADC (absolute, Y)
case 0x7d: this.ADC(this.AbsoluteXRead()); break; // ADC (absolute, X)
case 0x7e: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.ROR()); break; // ROR (absolute, X)
case 0x81: this.IndexedIndirectXAddress(); this.MemoryWrite(this.A); break; // STA (indexed indirect X)
case 0x82: this.FetchByte(); break; // *NOP (immediate)
case 0x82: _ = this.FetchByte(); break; // *NOP (immediate)
case 0x84: this.ZeroPageAddress(); this.MemoryWrite(this.Y); break; // STY (zero page)
case 0x85: this.ZeroPageAddress(); this.MemoryWrite(this.A); break; // STA (zero page)
case 0x86: this.ZeroPageAddress(); this.MemoryWrite(this.X); break; // STX (zero page)
@@ -428,21 +428,21 @@ namespace M6502
case 0x9a: this.SwallowRead(); this.S = this.X; break; // TXS (implied)
case 0x9d: this.AbsoluteXAddress(); this.Fixup(); this.MemoryWrite(this.A); break; // STA (absolute, X)
case 0xa0: this.FetchByte(); this.Y = this.Through(); break; // LDY (immediate)
case 0xa1: this.IndexedIndirectXRead(); this.A = this.Through(); break; // LDA (indexed indirect X)
case 0xa2: this.FetchByte(); this.X = this.Through(); break; // LDX (immediate)
case 0xa0: this.Y = this.Through(this.FetchByte()); break; // LDY (immediate)
case 0xa1: this.A = this.Through(this.IndexedIndirectXRead()); break; // LDA (indexed indirect X)
case 0xa2: this.X = this.Through(this.FetchByte()); break; // LDX (immediate)
case 0xa4: this.ZeroPageRead(); this.Y = this.Through(); break; // LDY (zero page)
case 0xa5: this.ZeroPageRead(); this.A = this.Through(); break; // LDA (zero page)
case 0xa6: this.ZeroPageRead(); this.X = this.Through(); break; // LDX (zero page)
case 0xa8: this.SwallowRead(); this.Y = this.Through(this.A); break; // TAY (implied)
case 0xa9: this.FetchByte(); this.A = this.Through(); break; // LDA (immediate)
case 0xa9: this.A = this.Through(this.FetchByte()); break; // LDA (immediate)
case 0xaa: this.SwallowRead(); this.X = this.Through(this.A); break; // TAX (implied)
case 0xac: this.AbsoluteRead(); this.Y = this.Through(); break; // LDY (absolute)
case 0xad: this.AbsoluteRead(); this.A = this.Through(); break; // LDA (absolute)
case 0xae: this.AbsoluteRead(); this.X = this.Through(); break; // LDX (absolute)
case 0xac: this.Y = this.Through(this.AbsoluteRead()); break; // LDY (absolute)
case 0xad: this.A = this.Through(this.AbsoluteRead()); break; // LDA (absolute)
case 0xae: this.X = this.Through(this.AbsoluteRead()); break; // LDX (absolute)
case 0xb0: this.Branch(this.Carry); break; // BCS (relative)
case 0xb1: this.IndirectIndexedYRead(); this.A = this.Through(); break; // LDA (indirect indexed Y)
case 0xb1: this.A = this.Through(this.IndirectIndexedYRead()); break; // LDA (indirect indexed Y)
case 0xb4: this.ZeroPageXRead(); this.Y = this.Through(); break; // LDY (zero page, X)
case 0xb5: this.ZeroPageXRead(); this.A = this.Through(); break; // LDA (zero page, X)
case 0xb6: this.ZeroPageYRead(); this.X = this.Through(); break; // LDX (zero page, Y)
@@ -453,39 +453,39 @@ namespace M6502
case 0xbd: this.AbsoluteXRead(); this.A = this.Through(); break; // LDA (absolute, X)
case 0xbe: this.AbsoluteYRead(); this.X = this.Through(); break; // LDX (absolute, Y)
case 0xc0: this.FetchByte(); this.CMP(this.Y); break; // CPY (immediate)
case 0xc1: this.IndexedIndirectXRead(); this.CMP(this.A); break; // CMP (indexed indirect X)
case 0xc2: this.FetchByte(); break; // *NOP (immediate)
case 0xc4: this.ZeroPageRead(); this.CMP(this.Y); break; // CPY (zero page)
case 0xc5: this.ZeroPageRead(); this.CMP(this.A); break; // CMP (zero page)
case 0xc0: this.CMP(this.Y, this.FetchByte()); break; // CPY (immediate)
case 0xc1: this.CMP(this.A, this.IndexedIndirectXRead()); break; // CMP (indexed indirect X)
case 0xc2: _ = this.FetchByte(); break; // *NOP (immediate)
case 0xc4: this.CMP(this.Y, this.ZeroPageRead()); break; // CPY (zero page)
case 0xc5: this.CMP(this.A, this.ZeroPageRead()); break; // CMP (zero page)
case 0xc6: this.ZeroPageRead(); this.ModifyWrite(this.DEC()); break; // DEC (zero page)
case 0xc8: this.SwallowRead(); this.Y = this.INC(this.Y); break; // INY (implied)
case 0xc9: this.FetchByte(); this.CMP(this.A); break; // CMP (immediate)
case 0xc9: this.CMP(this.A, this.FetchByte()); break; // CMP (immediate)
case 0xca: this.SwallowRead(); this.X = this.DEC(this.X); break; // DEX (implied)
case 0xcc: this.AbsoluteRead(); this.CMP(this.Y); break; // CPY (absolute)
case 0xcd: this.AbsoluteRead(); this.CMP(this.A); break; // CMP (absolute)
case 0xcc: this.CMP(this.Y, this.AbsoluteRead()); break; // CPY (absolute)
case 0xcd: this.CMP(this.A, this.AbsoluteRead()); break; // CMP (absolute)
case 0xce: this.AbsoluteRead(); this.ModifyWrite(this.DEC()); break; // DEC (absolute)
case 0xd0: this.BranchNot(this.Zero); break; // BNE (relative)
case 0xd1: this.IndirectIndexedYRead(); this.CMP(this.A); break; // CMP (indirect indexed Y)
case 0xd1: this.CMP(this.A, this.IndirectIndexedYRead()); break; // CMP (indirect indexed Y)
case 0xd4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
case 0xd5: this.ZeroPageXRead(); this.CMP(this.A); break; // CMP (zero page, X)
case 0xd5: this.CMP(this.A, this.ZeroPageXRead()); break; // CMP (zero page, X)
case 0xd6: this.ZeroPageXRead(); this.ModifyWrite(this.DEC()); break; // DEC (zero page, X)
case 0xd8: this.SwallowRead(); this.ResetFlag(StatusBits.DF); break; // CLD (implied)
case 0xd9: this.AbsoluteYRead(); this.CMP(this.A); break; // CMP (absolute, Y)
case 0xdd: this.AbsoluteXRead(); this.CMP(this.A); break; // CMP (absolute, X)
case 0xd9: this.CMP(this.A, this.AbsoluteYRead()); break; // CMP (absolute, Y)
case 0xdd: this.CMP(this.A, this.AbsoluteXRead()); break; // CMP (absolute, X)
case 0xde: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.DEC()); break; // DEC (absolute, X)
case 0xe0: this.FetchByte(); this.CMP(this.X); break; // CPX (immediate)
case 0xe0: this.CMP(this.X, this.FetchByte()); break; // CPX (immediate)
case 0xe1: this.IndexedIndirectXRead(); this.SBC(); break; // SBC (indexed indirect X)
case 0xe2: this.FetchByte(); break; // *NOP (immediate)
case 0xe4: this.ZeroPageRead(); this.CMP(this.X); break; // CPX (zero page)
case 0xe2: _ = this.FetchByte(); break; // *NOP (immediate)
case 0xe4: this.CMP(this.X, this.ZeroPageRead()); break; // CPX (zero page)
case 0xe5: this.ZeroPageRead(); this.SBC(); break; // SBC (zero page)
case 0xe6: this.ZeroPageRead(); this.ModifyWrite(this.INC()); break; // INC (zero page)
case 0xe8: this.SwallowRead(); this.X = this.INC(this.X); break; // INX (implied)
case 0xe9: this.FetchByte(); this.SBC(); break; // SBC (immediate)
case 0xe9: _ = this.FetchByte(); this.SBC(); break; // SBC (immediate)
case 0xea: this.SwallowRead(); break; // NOP (implied)
case 0xec: this.AbsoluteRead(); this.CMP(this.X); break; // CPX (absolute)
case 0xec: this.CMP(this.X, this.AbsoluteRead()); break; // CPX (absolute)
case 0xed: this.AbsoluteRead(); this.SBC(); break; // SBC (absolute)
case 0xee: this.AbsoluteRead(); this.ModifyWrite(this.INC()); break; // INC (absolute)
@@ -543,7 +543,7 @@ namespace M6502
// Can't use "FetchByte", since that would add an extra tick.
this.ImmediateAddress();
_ = this.ReadFromBus();
this.ReadFromBus();
System.Diagnostics.Debug.Assert(this.Cycles == 1, "BUS read has introduced stray cycles");
this.RaiseSYNC();
@@ -631,16 +631,16 @@ namespace M6502
protected abstract void Fixup();
protected void MaybeFixupRead()
protected byte MaybeFixupRead()
{
this.MaybeFixup();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void FixupRead()
protected byte FixupRead()
{
this.Fixup();
_ = this.MemoryRead();
return this.MemoryRead();
}
#endregion
@@ -711,52 +711,52 @@ namespace M6502
#region Address and read
protected void AbsoluteRead()
protected byte AbsoluteRead()
{
this.AbsoluteAddress();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void ZeroPageRead()
protected byte ZeroPageRead()
{
this.ZeroPageAddress();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void ZeroPageXRead()
protected byte ZeroPageXRead()
{
this.ZeroPageXAddress();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void ZeroPageYRead()
protected byte ZeroPageYRead()
{
this.ZeroPageYAddress();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void IndexedIndirectXRead()
protected byte IndexedIndirectXRead()
{
this.IndexedIndirectXAddress();
_ = this.MemoryRead();
return this.MemoryRead();
}
protected void AbsoluteXRead()
protected byte AbsoluteXRead()
{
this.AbsoluteXAddress();
this.MaybeFixupRead();
return this.MaybeFixupRead();
}
protected void AbsoluteYRead()
protected byte AbsoluteYRead()
{
this.AbsoluteYAddress();
this.MaybeFixupRead();
return this.MaybeFixupRead();
}
protected void IndirectIndexedYRead()
protected byte IndirectIndexedYRead()
{
this.IndirectIndexedYAddress();
this.MaybeFixupRead();
return this.MaybeFixupRead();
}
#endregion
@@ -771,7 +771,7 @@ namespace M6502
protected void Branch(bool condition)
{
this.FetchByte();
_ = this.FetchByte();
if (condition)
{
var relative = (sbyte)this.Bus.Data;
@@ -876,12 +876,11 @@ namespace M6502
this.SetFlag(StatusBits.VF, NegativeTest((byte)(~(operand ^ data) & (operand ^ intermediate))));
}
protected void ADC() => this.A = this.DecimalMasked != 0 ? this.DecimalADC() : this.BinaryADC();
protected void ADC(byte data) => this.A = this.DecimalMasked != 0 ? this.DecimalADC(data) : this.BinaryADC(data);
private byte BinaryADC()
private byte BinaryADC(byte data)
{
var operand = this.A;
var data = this.Bus.Data;
this.Intermediate.Word = (ushort)(operand + data + this.Carry);
this.AdjustOverflowAdd(operand);
@@ -892,10 +891,9 @@ namespace M6502
return this.Intermediate.Low;
}
private byte DecimalADC()
private byte DecimalADC(byte data)
{
var operand = this.A;
var data = this.Bus.Data;
var low = (ushort)(LowerNibble(operand) + LowerNibble(data) + this.Carry);
this.Intermediate.Word = (ushort)(HigherNibble(operand) + HigherNibble(data));
@@ -929,11 +927,17 @@ namespace M6502
#region Bitwise operations
protected void OrR() => this.A = this.Through(this.A | this.Bus.Data);
protected void OrR(byte data) => this.A = this.Through(this.A | data);
protected void AndR() => this.A = this.Through(this.A & this.Bus.Data);
protected void OrR() => this.OrR(this.Bus.Data);
protected void EorR() => this.A = this.Through(this.A ^ this.Bus.Data);
protected void AndR(byte data) => this.A = this.Through(this.A & data);
protected void AndR() => this.AndR(this.Bus.Data);
protected void EorR(byte data) => this.A = this.Through(this.A ^ data);
protected void EorR() => this.EorR(this.Bus.Data);
protected void BIT()
{
@@ -945,9 +949,8 @@ namespace M6502
#endregion
protected void CMP(byte first)
protected void CMP(byte first, byte second)
{
var second = this.Bus.Data;
this.Intermediate.Word = (ushort)(first - second);
this.AdjustNZ(this.Intermediate.Low);
this.ResetFlag(StatusBits.CF, this.Intermediate.High);
@@ -981,7 +984,8 @@ namespace M6502
private void PLP()
{
this.SwallowPop();
this.P = ClearBit(SetBit(this.Pop(), StatusBits.RF), StatusBits.BF);
this.Pop();
this.P = ClearBit(SetBit(this.Bus.Data, StatusBits.RF), StatusBits.BF);
}
private void RTI()

View File

@@ -323,7 +323,7 @@ namespace M6502
private void RRA()
{
this.ModifyWrite(this.ROR());
this.ADC();
this.ADC(this.Bus.Data);
}
private void SLO()
@@ -341,7 +341,7 @@ namespace M6502
private void DCP()
{
this.ModifyWrite(this.DEC());
this.CMP(this.A);
this.CMP(this.A, this.Bus.Data);
}
#endregion

View File

@@ -61,7 +61,7 @@ namespace M6502
case 0x0c: this.AbsoluteRead(); this.TSB(); break; // TSB a
case 0x0f: this.ZeroPageRead(); this.BBR(Bit(0)); break; // BBR0 r
case 0x12: this.ZeroPageIndirectRead(); this.OrR(); break; // ORA (zp),y
case 0x12: this.OrR(this.ZeroPageIndirectRead()); break; // ORA (zp),y
case 0x13: break; // null
case 0x14: this.ZeroPageRead(); this.TRB(); break; // TRB zp
case 0x17: this.ZeroPageRead(); this.RMB(Bit(1)); break; // RMB1 zp
@@ -109,11 +109,11 @@ namespace M6502
case 0x6b: break; // null
case 0x6f: this.ZeroPageRead(); this.BBR(Bit(6)); break; // BBR6 r
case 0x72: this.ZeroPageIndirectRead(); this.ADC(); break; // ADC (zp)
case 0x72: this.ADC(this.ZeroPageIndirectRead()); break; // ADC (zp)
case 0x73: break; // null
case 0x74: this.ZeroPageXAddress(); this.MemoryWrite(0); break; // STZ zp,x
case 0x77: this.ZeroPageRead(); this.RMB(Bit(7)); break; // RMB7 zp
case 0x7a: this.SwallowRead(); this.SwallowPop(); this.Y = this.Through(this.Pop()); break; // PLY s
case 0x7a: this.SwallowRead(); this.SwallowPop(); this.Pop(); this.Y = this.Through(); break; // PLY s
case 0x7b: break; // null
case 0x7c: this.AbsoluteXAddress(); this.Bus.Address.Assign(this.Intermediate); this.GetAddressPaged(); this.Jump(this.Bus.Address); break; // JMP (a,x)
case 0x7f: this.ZeroPageRead(); this.BBR(Bit(7)); break; // BBR7 r
@@ -149,7 +149,7 @@ namespace M6502
case 0xcb: this.SwallowRead(); this.Waiting = true; break; // WAI i
case 0xcf: this.ZeroPageRead(); this.BBS(Bit(4)); break; // BBS4 r
case 0xd2: this.ZeroPageIndirectRead(); this.CMP(this.A); break; // CMP (zp)
case 0xd2: this.CMP(this.A, this.ZeroPageIndirectRead()); break; // CMP (zp)
case 0xd3: break; // null
case 0xd7: this.ZeroPageRead(); this.SMB(Bit(5)); break; // SMB5 zp
case 0xda: this.SwallowRead(); this.Push(this.X); break; // PHX s
@@ -165,7 +165,7 @@ namespace M6502
case 0xf2: this.ZeroPageIndirectRead(); this.SBC(); break; // SBC (zp)
case 0xf3: break; // null
case 0xf7: this.ZeroPageRead(); this.SMB(Bit(7)); break; // SMB7 zp
case 0xfa: this.SwallowRead(); this.SwallowPop(); this.X = this.Through(this.Pop()); break; // PLX s
case 0xfa: this.SwallowRead(); this.SwallowPop(); this.Pop(); this.X = this.Through(); break; // PLX s
case 0xfb: break; // null
case 0xfc: break; // null
case 0xff: this.ZeroPageRead(); this.BBS(Bit(7)); break; // BBS7 r
@@ -263,10 +263,10 @@ namespace M6502
#region Address and read
private void ZeroPageIndirectRead()
private byte ZeroPageIndirectRead()
{
this.ZeroPageIndirectAddress();
this.MemoryRead();
return this.MemoryRead();
}
#endregion
@@ -290,7 +290,7 @@ namespace M6502
private void BranchBit(bool condition)
{
this.FetchByte();
_ = this.FetchByte();
if (condition)
{
var relative = (sbyte)this.Bus.Data;

View File

@@ -2,17 +2,18 @@
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
namespace MC6809.Test
{
using EightBit;
using System;
public sealed class Board : Bus
{
private readonly Configuration configuration;
private readonly Ram ram = new Ram(0x8000); // 0000 - 7FFF, 32K RAM
private readonly UnusedMemory unused2000 = new UnusedMemory(0x2000, 0xff); // 8000 - 9FFF, 8K unused
private readonly Ram io = new Ram(0x2000); // A000 - BFFF, 8K serial interface, minimally decoded
private readonly Rom rom = new Rom(0x4000); // C000 - FFFF, 16K ROM
private readonly Ram ram = new(0x8000); // 0000 - 7FFF, 32K RAM
private readonly UnusedMemory unused2000 = new(0x2000, 0xff); // 8000 - 9FFF, 8K unused
private readonly Ram io = new(0x2000); // A000 - BFFF, 8K serial interface, minimally decoded
private readonly Rom rom = new(0x4000); // C000 - FFFF, 16K ROM
private readonly Disassembler disassembler;
private readonly Profiler profiler;
@@ -27,9 +28,9 @@ namespace EightBit
public Board(Configuration configuration)
{
this.configuration = configuration;
this.CPU = new MC6809(this);
this.disassembler = new Disassembler(this, this.CPU);
this.profiler = new Profiler(this, this.CPU, this.disassembler);
CPU = new MC6809(this);
disassembler = new Disassembler(this, CPU);
profiler = new Profiler(this, CPU, disassembler);
}
public MC6809 CPU { get; }
@@ -40,20 +41,20 @@ namespace EightBit
{
if (absolute < 0x8000)
{
return new MemoryMapping(this.ram, 0x0000, Mask.Sixteen, AccessLevel.ReadWrite);
return new MemoryMapping(ram, 0x0000, Mask.Sixteen, AccessLevel.ReadWrite);
}
if (absolute < 0xa000)
{
return new MemoryMapping(this.unused2000, 0x8000, Mask.Sixteen, AccessLevel.ReadOnly);
return new MemoryMapping(unused2000, 0x8000, Mask.Sixteen, AccessLevel.ReadOnly);
}
if (absolute < 0xc000)
{
return new MemoryMapping(this.io, 0xa000, Mask.Sixteen, AccessLevel.ReadWrite);
return new MemoryMapping(io, 0xa000, Mask.Sixteen, AccessLevel.ReadWrite);
}
return new MemoryMapping(this.rom, 0xc000, Mask.Sixteen, AccessLevel.ReadOnly);
return new MemoryMapping(rom, 0xc000, Mask.Sixteen, AccessLevel.ReadOnly);
}
public override void RaisePOWER()
@@ -61,166 +62,167 @@ namespace EightBit
base.RaisePOWER();
// Get the CPU ready for action
this.CPU.RaisePOWER();
this.CPU.LowerRESET();
this.CPU.RaiseINT();
this.CPU.RaiseNMI();
this.CPU.RaiseFIRQ();
this.CPU.RaiseHALT();
CPU.RaisePOWER();
CPU.LowerRESET();
CPU.RaiseINT();
CPU.RaiseNMI();
CPU.RaiseFIRQ();
CPU.RaiseHALT();
// Get the ACIA ready for action
this.Address.Word = 0b1010000000000000;
this.Data = (byte)(MC6850.ControlRegister.CR0 | MC6850.ControlRegister.CR1); // Master reset
this.ACIA.CTS.Lower();
this.ACIA.RW.Lower();
this.UpdateAciaPins();
this.ACIA.RaisePOWER();
this.AccessAcia();
Address.Word = 0b1010000000000000;
Data = (byte)(MC6850.ControlRegister.CR0 | MC6850.ControlRegister.CR1); // Master reset
ACIA.CTS.Lower();
ACIA.RW.Lower();
UpdateAciaPins();
ACIA.RaisePOWER();
AccessAcia();
}
public override void LowerPOWER()
{
////this.profiler.Generate();
this.ACIA.LowerPOWER();
this.CPU.LowerPOWER();
ACIA.LowerPOWER();
CPU.LowerPOWER();
base.LowerPOWER();
}
public override void Initialize()
{
System.Console.TreatControlCAsInput = true;
Console.TreatControlCAsInput = true;
// Load our BASIC interpreter
var directory = this.configuration.RomDirectory + "\\";
this.LoadHexFile(directory + "ExBasROM.hex");
var directory = configuration.RomDirectory + "\\";
LoadHexFile(directory + "ExBasROM.hex");
// Catch a byte being transmitted
this.ACIA.Transmitting += this.ACIA_Transmitting;
ACIA.Transmitting += ACIA_Transmitting;
// Keyboard wiring, check for input once per frame
this.CPU.ExecutedInstruction += this.CPU_ExecutedInstruction;
CPU.ExecutedInstruction += CPU_ExecutedInstruction;
if (this.configuration.DebugMode)
// Marshal data from ACIA -> memory
this.ReadingByte += Board_ReadingByte;
// Marshal data from memory -> ACIA
this.WrittenByte += Board_WrittenByte;
if (configuration.DebugMode)
{
// MC6809 disassembly wiring
this.CPU.ExecutingInstruction += this.CPU_ExecutingInstruction;
this.CPU.ExecutedInstruction += this.CPU_ExecutedInstruction_Debug;
CPU.ExecutingInstruction += CPU_ExecutingInstruction;
CPU.ExecutedInstruction += CPU_ExecutedInstruction_Debug;
}
if (this.configuration.TerminatesEarly)
if (configuration.TerminatesEarly)
{
// Early termination condition for CPU timing code
this.CPU.ExecutedInstruction += this.CPU_ExecutedInstruction_Termination;
CPU.ExecutedInstruction += CPU_ExecutedInstruction_Termination;
}
////this.profiler.Enable();
////this.profiler.EmitLine += this.Profiler_EmitLine;
}
// Marshal data from ACIA -> memory
protected override void OnReadingByte()
private void Board_ReadingByte(object? sender, EventArgs e)
{
this.UpdateAciaPins();
this.ACIA.RW.Raise();
if (this.AccessAcia())
UpdateAciaPins();
ACIA.RW.Raise();
if (AccessAcia())
{
this.Poke(this.ACIA.DATA);
}
base.OnReadingByte();
}
// Marshal data from memory -> ACIA
protected override void OnWrittenByte()
{
base.OnWrittenByte();
this.UpdateAciaPins();
if (this.ACIA.Selected)
{
this.ACIA.RW.Lower();
this.AccessAcia();
Poke(ACIA.DATA);
}
}
private void Profiler_EmitLine(object sender, ProfileLineEventArgs e)
private void Board_WrittenByte(object? sender, EventArgs e)
{
UpdateAciaPins();
if (ACIA.Selected)
{
ACIA.RW.Lower();
AccessAcia();
}
}
private void Profiler_EmitLine(object? sender, ProfileLineEventArgs e)
{
var cycles = e.Cycles;
var disassembled = e.Source;
System.Console.Error.WriteLine(disassembled);
Console.Error.WriteLine(disassembled);
}
private void CPU_ExecutedInstruction_Termination(object sender, EventArgs e)
private void CPU_ExecutedInstruction_Termination(object? sender, EventArgs e)
{
this.totalCycleCount += (ulong)this.CPU.Cycles;
if (this.totalCycleCount > Configuration.TerminationCycles)
totalCycleCount += (ulong)CPU.Cycles;
if (totalCycleCount > Configuration.TerminationCycles)
{
this.LowerPOWER();
LowerPOWER();
}
}
private void CPU_ExecutedInstruction_Debug(object sender, EventArgs e)
private void CPU_ExecutedInstruction_Debug(object? sender, EventArgs e)
{
if (!this.ignoreDisassembly)
if (!ignoreDisassembly)
{
var disassembled = $"{this.disassembler.Trace(this.disassembleAt)}\t{this.ACIA.DumpStatus()}";
System.Console.Error.WriteLine(disassembled);
var disassembled = $"{disassembler.Trace(disassembleAt)}\t{ACIA.DumpStatus()}";
Console.Error.WriteLine(disassembled);
}
}
private void CPU_ExecutingInstruction(object sender, EventArgs e)
private void CPU_ExecutingInstruction(object? sender, EventArgs e)
{
this.disassembleAt = this.CPU.PC.Word;
this.ignoreDisassembly = this.disassembler.Ignore || this.disassembler.Pause;
disassembleAt = CPU.PC.Word;
ignoreDisassembly = disassembler.Ignore || disassembler.Pause;
}
private void CPU_ExecutedInstruction(object sender, EventArgs e)
private void CPU_ExecutedInstruction(object? sender, EventArgs e)
{
this.frameCycleCount -= this.CPU.Cycles;
if (this.frameCycleCount < 0)
frameCycleCount -= CPU.Cycles;
if (frameCycleCount < 0)
{
if (System.Console.KeyAvailable)
if (Console.KeyAvailable)
{
var key = System.Console.ReadKey(true);
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.F12)
{
this.LowerPOWER();
LowerPOWER();
}
this.ACIA.RDR = System.Convert.ToByte(key.KeyChar);
this.ACIA.MarkReceiveStarting();
ACIA.RDR = Convert.ToByte(key.KeyChar);
ACIA.MarkReceiveStarting();
}
this.frameCycleCount = (long)Configuration.FrameCycleInterval;
frameCycleCount = (long)Configuration.FrameCycleInterval;
}
}
private void ACIA_Transmitting(object sender, EventArgs e)
private void ACIA_Transmitting(object? sender, EventArgs e)
{
System.Console.Out.Write(Convert.ToChar(this.ACIA.TDR));
this.ACIA.MarkTransmitComplete();
Console.Out.Write(Convert.ToChar(ACIA.TDR));
ACIA.MarkTransmitComplete();
}
private void UpdateAciaPins()
{
this.ACIA.DATA = this.Data;
this.ACIA.RS.Match(this.Address.Word & (ushort)Bits.Bit0);
this.ACIA.CS0.Match(this.Address.Word & (ushort)Bits.Bit15);
this.ACIA.CS1.Match(this.Address.Word & (ushort)Bits.Bit13);
this.ACIA.CS2.Match(this.Address.Word & (ushort)Bits.Bit14);
ACIA.DATA = Data;
ACIA.RS.Match(Address.Word & (ushort)Bits.Bit0);
ACIA.CS0.Match(Address.Word & (ushort)Bits.Bit15);
ACIA.CS1.Match(Address.Word & (ushort)Bits.Bit13);
ACIA.CS2.Match(Address.Word & (ushort)Bits.Bit14);
}
private bool AccessAcia()
{
this.ACIA.E.Raise();
ACIA.E.Raise();
try
{
this.ACIA.Tick();
return this.ACIA.Activated;
ACIA.Tick();
return ACIA.Activated;
}
finally
{
this.ACIA.E.Lower();
ACIA.E.Lower();
}
}
}

View File

@@ -4,6 +4,7 @@
namespace EightBit
{
using MC6809.Test;
using System.Diagnostics;
internal sealed class TestHarness(Configuration configuration)

View File

@@ -580,17 +580,19 @@ namespace MC6809
private byte Pop(Register16 stack)
{
var read = this.MemoryRead(stack);
_ = this.MemoryRead(stack);
stack.Increment();
return read;
return this.Bus.Data;
}
private byte PopS() => this.Pop(this.S);
private Register16 PopWord(Register16 stack)
{
this.Intermediate.High = this.Pop(stack);
this.Intermediate.Low = this.Pop(stack);
this.Pop(stack);
this.Intermediate.High = this.Bus.Data;
this.Pop(stack);
this.Intermediate.Low = this.Bus.Data;
return this.Intermediate;
}
@@ -600,7 +602,8 @@ namespace MC6809
private Register16 Address_relative_byte()
{
var offset = (sbyte)this.FetchByte();
this.FetchByte();
var offset = (sbyte)this.Bus.Data;
this.Intermediate.Word = (ushort)(this.PC.Word + offset);
return this.Intermediate;
}
@@ -614,7 +617,8 @@ namespace MC6809
private Register16 Address_direct()
{
this.Intermediate.Assign(this.FetchByte(), this.DP);
this.FetchByte();
this.Intermediate.Assign(this.Bus.Data, this.DP);
return this.Intermediate;
}
@@ -634,7 +638,8 @@ namespace MC6809
private Register16 Address_indexed()
{
var type = this.FetchByte();
this.FetchByte();
var type = this.Bus.Data;
var r = this.RR((type & (byte)(Bits.Bit6 | Bits.Bit5)) >> 5);
if ((type & (byte)Bits.Bit7) != 0)
@@ -672,7 +677,8 @@ namespace MC6809
break;
case 0b1000: // n,R (eight-bit)
this.Tick();
this.Intermediate.Word = (ushort)(r.Word + (sbyte)this.FetchByte());
this.FetchByte();
this.Intermediate.Word = (ushort)(r.Word + (sbyte)this.Bus.Data);
break;
case 0b1001: // n,R (sixteen-bit)
this.Tick(4);
@@ -715,13 +721,29 @@ namespace MC6809
return this.Intermediate;
}
private byte AM_immediate_byte() => this.FetchByte();
private byte AM_immediate_byte()
{
this.FetchByte();
return this.Bus.Data;
}
private byte AM_direct_byte() => this.MemoryRead(this.Address_direct());
private byte AM_direct_byte()
{
this.MemoryRead(this.Address_direct());
return this.Bus.Data;
}
private byte AM_indexed_byte() => this.MemoryRead(this.Address_indexed());
private byte AM_indexed_byte()
{
this.MemoryRead(this.Address_indexed());
return this.Bus.Data;
}
private byte AM_extended_byte() => this.MemoryRead(this.Address_extended());
private byte AM_extended_byte()
{
this.MemoryRead(this.Address_extended());
return this.Bus.Data;
}
private Register16 AM_immediate_word() => this.FetchWord();
@@ -859,25 +881,29 @@ namespace MC6809
if ((data & (byte)Bits.Bit0) != 0)
{
this.Tick();
this.CC = this.Pop(stack);
this.Pop(stack);
this.CC = this.Bus.Data;
}
if ((data & (byte)Bits.Bit1) != 0)
{
this.Tick();
this.A = this.Pop(stack);
this.Pop(stack);
this.A = this.Bus.Data;
}
if ((data & (byte)Bits.Bit2) != 0)
{
this.Tick();
this.B = this.Pop(stack);
this.Pop(stack);
this.B = this.Bus.Data;
}
if ((data & (byte)Bits.Bit3) != 0)
{
this.Tick();
this.DP = this.Pop(stack);
this.Pop(stack);
this.DP = this.Bus.Data;
}
if ((data & (byte)Bits.Bit4) != 0)
@@ -1050,7 +1076,8 @@ namespace MC6809
}
else
{
this.Execute(this.FetchByte());
this.FetchByte();
this.Execute(this.Bus.Data);
}
}
@@ -1079,8 +1106,8 @@ namespace MC6809
{
switch (this.OpCode)
{
case 0x10: this.prefix10 = true; this.Execute(this.FetchByte()); break;
case 0x11: this.prefix11 = true; this.Execute(this.FetchByte()); break;
case 0x10: this.prefix10 = true; this.FetchByte(); this.Execute(this.Bus.Data); break;
case 0x11: this.prefix11 = true; this.FetchByte(); this.Execute(this.Bus.Data); break;
// ABX
case 0x3a: this.Tick(3); this.X.Word += this.B; break; // ABX (inherent)

View File

@@ -549,14 +549,14 @@ namespace Z80
private byte ReadDataUnderInterrupt()
{
this.LowerM1();
this.Tick(3);
this.LowerIORQ();
this.Tick();
_ = this.Bus.Data;
this.RaiseIORQ();
Debug.Assert(this.Cycles == 4);
this.RefreshMemory();
Debug.Assert(this.Cycles == 5);
this.Tick(3);
this.LowerIORQ();
this.Tick();
_ = this.Bus.Data;
this.RaiseIORQ();
Debug.Assert(this.Cycles == 4);
this.RefreshMemory();
Debug.Assert(this.Cycles == 5);
this.RaiseM1();
return this.Bus.Data;
}
@@ -933,7 +933,7 @@ namespace Z80
switch (z)
{
case 0: // Input from port with 16-bit address
this.ReadPort(this.BC);
_ = this.ReadPort(this.BC);
this.MEMPTR.Increment();
if (y != 6)
{
@@ -1149,7 +1149,7 @@ namespace Z80
break;
case 2: // DJNZ d
this.Tick();
_ = this.JumpRelativeConditional(--this.B != 0);
this.JumpRelativeConditional(--this.B != 0);
break;
case 3: // JR d
this.JumpRelative(this.FetchByte());
@@ -1158,7 +1158,7 @@ namespace Z80
case 5:
case 6:
case 7:
_ = this.JumpRelativeConditionalFlag(y - 4);
this.JumpRelativeConditionalFlag(y - 4);
break;
default:
throw new NotSupportedException("Invalid operation mode");
@@ -1197,7 +1197,7 @@ namespace Z80
this.SetWord(this.HL2());
break;
case 3: // LD (nn),A
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
WriteMemoryIndirect(this.A);
break;
default:
@@ -1219,7 +1219,7 @@ namespace Z80
this.HL2().Assign(this.GetWord());
break;
case 3: // LD A,(nn)
this.FetchWordMEMPTR();
this.FetchInto(this.MEMPTR);
this.A = this.ReadMemoryIndirect();
break;
default:
@@ -1270,14 +1270,12 @@ namespace Z80
this.FetchDisplacement();
}
_ = this.FetchByte(); // LD r,n
if (memoryY)
{
var value = this.FetchByte(); // LD r,n
if (memoryY)
{
this.Tick(2);
}
this.R(y, value);
this.Tick(2);
}
this.R(y, this.Bus.Data);
break;
case 7: // Assorted operations on accumulator/flags
@@ -1422,13 +1420,13 @@ namespace Z80
switch (z)
{
case 0: // Conditional return
_ = this.ReturnConditionalFlag(y);
this.ReturnConditionalFlag(y);
break;
case 1: // POP & various ops
switch (q)
{
case 0: // POP rp2[p]
this.RP2(p).Assign(this.PopWord());
this.PopInto(this.RP2(p));
break;
case 1:
switch (p)
@@ -1457,7 +1455,7 @@ namespace Z80
break;
case 2: // Conditional jump
_ = this.JumpConditionalFlag(y);
this.JumpConditionalFlag(y);
break;
case 3: // Assorted operations
switch (y)
@@ -1482,8 +1480,7 @@ namespace Z80
this.WritePort(this.FetchByte());
break;
case 3: // IN A,(n)
this.ReadPort(this.FetchByte());
this.A = this.Bus.Data;
this.A = this.ReadPort(this.FetchByte());
break;
case 4: // EX (SP),HL
this.XHTL(this.HL2());
@@ -1504,7 +1501,7 @@ namespace Z80
break;
case 4: // Conditional call: CALL cc[y], nn
_ = this.CallConditionalFlag(y);
this.CallConditionalFlag(y);
break;
case 5: // PUSH & various ops
switch (q)
@@ -1682,7 +1679,7 @@ namespace Z80
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
};
protected sealed override bool ReturnConditionalFlag(int flag)
protected sealed override void ReturnConditionalFlag(int flag)
{
var condition = this.ConvertCondition(flag);
this.Tick();
@@ -1690,7 +1687,6 @@ namespace Z80
{
this.Return();
}
return condition;
}
private Register16 SBC(Register16 operand, Register16 value)
@@ -2041,7 +2037,7 @@ namespace Z80
private void BlockLoad()
{
this.MemoryRead(this.HL);
_ = this.MemoryRead(this.HL);
this.Bus.Address.Assign(this.DE);
this.MemoryUpdate(1);
this.Tick(2);
@@ -2142,7 +2138,7 @@ namespace Z80
private void BlockIn()
{
this.Tick();
this.ReadPort(this.BC);
_ = this.ReadPort(this.BC);
this.Bus.Address.Assign(this.HL);
this.MemoryUpdate(1);
this.AdjustSZXY(--this.B);
@@ -2357,20 +2353,21 @@ namespace Z80
this.Tick();
}
private void ReadPort(byte port)
private byte ReadPort(byte port)
{
this.Bus.Address.Assign(port, this.Bus.Data = this.A);
this.ReadPort();
_ = this.ReadPort();
this.MEMPTR.Increment();
return this.Bus.Data;
}
private void ReadPort(Register16 port)
private byte ReadPort(Register16 port)
{
this.Bus.Address.Assign(port);
this.ReadPort();
return this.ReadPort();
}
private void ReadPort()
private byte ReadPort()
{
this.MEMPTR.Assign(this.Bus.Address);
this.Tick(2);
@@ -2381,6 +2378,7 @@ namespace Z80
this.RaiseRD();
this.RaiseIORQ();
this.Tick();
return this.Bus.Data;
}
#endregion