Compare commits

7 Commits

Author SHA1 Message Date
tmerritt c4e1f233ae more chips
more docs
2025-08-02 11:17:23 -04:00
tmerritt 7ac8bd86ba MOS6520 looking mostly there. 2025-07-29 13:12:33 -04:00
tmerritt 8f6f9cb64d adds docs
working on widetick
2025-07-26 11:02:36 -04:00
tmerritt b40c3c503f box swap 2025-07-22 15:51:21 -04:00
tmerritt d5efabdd36 prep to do big tick method 2025-07-21 13:41:17 -04:00
tmerritt 7498489b03 RamRomComputer now reads from ROM and writes to RAM and reads back from RAM 2025-07-18 16:09:41 -04:00
tmerritt 2939e1cac5 Lots of stuff. 2025-07-17 11:51:05 -04:00
170 changed files with 8619 additions and 2447 deletions
-5
View File
@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mos6502.iml" filepath="$PROJECT_DIR$/.idea/mos6502.iml" />
</modules>
</component>
</project>
-13
View File
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/cli/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+2
View File
@@ -1 +1,3 @@
/target
*produced.asm
*produced.bin
+479
View File
@@ -0,0 +1,479 @@
STA $f3 ; [ 0x85 0xf3 ]
PLA ; [ 0x68 ]
STA $f1 ; [ 0x85 0xf1 ]
PLA ; [ 0x68 ]
STA $ef ; [ 0x85 0xef ]
STA $fa ; [ 0x85 0xfa ]
PLA ; [ 0x68 ]
STA $f0 ; [ 0x85 0xf0 ]
STA $fb ; [ 0x85 0xfb ]
STY $f4 ; [ 0x84 0xf4 ]
STX $f5 ; [ 0x86 0xf5 ]
TSX ; [ 0xba ]
STX $f2 ; [ 0x86 0xf2 ]
JSR $1e88 ; [ 0x20 0x88 0x1e ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JMP ($17fa) ; [ 0x6c 0xfa 0x17 ]
JMP ($17fe) ; [ 0x6c 0xfe 0x17 ]
LDX #$ff ; [ 0xa2 0xff ]
TXS ; [ 0x9a ]
STX $f2 ; [ 0x86 0xf2 ]
JSR $1e88 ; [ 0x20 0x88 0x1e ]
LDA #$ff ; [ 0xa9 0xff ]
STA $17f3 ; [ 0x8d 0xf3 0x17 ]
LDA #$01 ; [ 0xa9 0x01 ]
BIT $1740 ; [ 0x2c 0x40 0x17 ]
BNE #$19 ; [ 0xd0 0x19 ]
BMI #$f9 ; [ 0x30 0xf9 ]
LDA #$fc ; [ 0xa9 0xfc ]
CLC ; [ 0x18 ]
ADC #$01 ; [ 0x69 0x01 ]
BCC $03 ; [ 0x90 0x03 ]
INC $17f3 ; [ 0xee 0xf3 0x17 ]
LDY $1740 ; [ 0xac 0x40 0x17 ]
BPL #$f3 ; [ 0x10 0xf3 ]
STA $17f2 ; [ 0x8d 0xf2 0x17 ]
LDX #$08 ; [ 0xa2 0x08 ]
JSR $1e6a ; [ 0x20 0x6a 0x1e ]
JSR $1e8c ; [ 0x20 0x8c 0x1e ]
LDA #$01 ; [ 0xa9 0x01 ]
BIT $1740 ; [ 0x2c 0x40 0x17 ]
BNE #$1e ; [ 0xd0 0x1e ]
JSR $1e2f ; [ 0x20 0x2f 0x1e ]
LDX #$0a ; [ 0xa2 0x0a ]
JSR $1e31 ; [ 0x20 0x31 0x1e ]
JMP $1daf ; [ 0x4c 0xaf 0x1d ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $f8 ; [ 0x85 0xf8 ]
STA $f9 ; [ 0x85 0xf9 ]
JSR $1e5a ; [ 0x20 0x5a 0x1e ]
CMP #$01 ; [ 0xc9 0x01 ]
BEQ $06 ; [ 0xf0 0x06 ]
JSR $1fac ; [ 0x20 0xac 0x1f ]
JMP $1ddb ; [ 0x4c 0xdb 0x1d ]
JSR $1f19 ; [ 0x20 0x19 0x1f ]
BNE #$d3 ; [ 0xd0 0xd3 ]
LDA #$01 ; [ 0xa9 0x01 ]
BIT $1740 ; [ 0x2c 0x40 0x17 ]
BEQ $cc ; [ 0xf0 0xcc ]
JSR $1f19 ; [ 0x20 0x19 0x1f ]
BEQ $f4 ; [ 0xf0 0xf4 ]
JSR $1f19 ; [ 0x20 0x19 0x1f ]
BEQ $ef ; [ 0xf0 0xef ]
JSR $1f6a ; [ 0x20 0x6a 0x1f ]
CMP #$15 ; [ 0xc9 0x15 ]
BPL #$bb ; [ 0x10 0xbb ]
CMP #$14 ; [ 0xc9 0x14 ]
BEQ $44 ; [ 0xf0 0x44 ]
CMP #$10 ; [ 0xc9 0x10 ]
BEQ $2c ; [ 0xf0 0x2c ]
CMP #$11 ; [ 0xc9 0x11 ]
BEQ $2c ; [ 0xf0 0x2c ]
CMP #$12 ; [ 0xc9 0x12 ]
BEQ $2f ; [ 0xf0 0x2f ]
CMP #$13 ; [ 0xc9 0x13 ]
BEQ $31 ; [ 0xf0 0x31 ]
ASL ; [ 0x0a ]
ASL ; [ 0x0a ]
ASL ; [ 0x0a ]
ASL ; [ 0x0a ]
STA $fc ; [ 0x85 0xfc ]
LDX #$04 ; [ 0xa2 0x04 ]
LDY $ff ; [ 0xa4 0xff ]
BNE #$0a ; [ 0xd0 0x0a ]
LDA ($fa),Y ; [ 0xb1 0xfa ]
ASL $fc ; [ 0x06 0xfc ]
ROL ; [ 0x2a ]
STA ($fa),Y ; [ 0x91 0xfa ]
JMP $1cc3 ; [ 0x4c 0xc3 0x1c ]
ASL ; [ 0x0a ]
ROL $fa ; [ 0x26 0xfa ]
ROL $fb ; [ 0x26 0xfb ]
DEX ; [ 0xca ]
BNE #$ea ; [ 0xd0 0xea ]
BEQ $08 ; [ 0xf0 0x08 ]
LDA #$01 ; [ 0xa9 0x01 ]
BNE #$02 ; [ 0xd0 0x02 ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $ff ; [ 0x85 0xff ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JSR $1f63 ; [ 0x20 0x63 0x1f ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JMP $1dc8 ; [ 0x4c 0xc8 0x1d ]
LDA $ef ; [ 0xa5 0xef ]
STA $fa ; [ 0x85 0xfa ]
LDA $f0 ; [ 0xa5 0xf0 ]
STA $fb ; [ 0x85 0xfb ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JSR $1e5a ; [ 0x20 0x5a 0x1e ]
CMP #$3b ; [ 0xc9 0x3b ]
BNE #$f9 ; [ 0xd0 0xf9 ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $f7 ; [ 0x85 0xf7 ]
STA $f6 ; [ 0x85 0xf6 ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
TAX ; [ 0xaa ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
STA $fb ; [ 0x85 0xfb ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
STA $fa ; [ 0x85 0xfa ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
TXA ; [ 0x8a ]
BEQ $0f ; [ 0xf0 0x0f ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
STA ($fa),Y ; [ 0x91 0xfa ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
JSR $1f63 ; [ 0x20 0x63 0x1f ]
DEX ; [ 0xca ]
BNE #$f2 ; [ 0xd0 0xf2 ]
INX ; [ 0xe8 ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
CMP $f6 ; [ 0xc5 0xf6 ]
BNE #$17 ; [ 0xd0 0x17 ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
CMP $f7 ; [ 0xc5 0xf7 ]
BNE #$13 ; [ 0xd0 0x13 ]
TXA ; [ 0x8a ]
BNE #$b9 ; [ 0xd0 0xb9 ]
LDX #$0c ; [ 0xa2 0x0c ]
LDA #$27 ; [ 0xa9 0x27 ]
STA $1742 ; [ 0x8d 0x42 0x17 ]
JSR $1e31 ; [ 0x20 0x31 0x1e ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JSR $1f9d ; [ 0x20 0x9d 0x1f ]
LDX #$11 ; [ 0xa2 0x11 ]
BNE #$ee ; [ 0xd0 0xee ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $f8 ; [ 0x85 0xf8 ]
STA $f9 ; [ 0x85 0xf9 ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $f6 ; [ 0x85 0xf6 ]
STA $f7 ; [ 0x85 0xf7 ]
JSR $1e2f ; [ 0x20 0x2f 0x1e ]
LDA #$3b ; [ 0xa9 0x3b ]
JSR $1ea0 ; [ 0x20 0xa0 0x1e ]
LDA $fa ; [ 0xa5 0xfa ]
CMP $17f7 ; [ 0xcd 0xf7 0x17 ]
LDA $fb ; [ 0xa5 0xfb ]
SBC $17f8 ; [ 0xed 0xf8 0x17 ]
BCC $18 ; [ 0x90 0x18 ]
LDA #$00 ; [ 0xa9 0x00 ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1fcc ; [ 0x20 0xcc 0x1f ]
JSR $1e1e ; [ 0x20 0x1e 0x1e ]
LDA $f6 ; [ 0xa5 0xf6 ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
LDA $f7 ; [ 0xa5 0xf7 ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JMP $1c64 ; [ 0x4c 0x64 0x1c ]
LDA #$18 ; [ 0xa9 0x18 ]
TAX ; [ 0xaa ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
JSR $1e1e ; [ 0x20 0x1e 0x1e ]
LDY #$00 ; [ 0xa0 0x00 ]
LDA ($fa),Y ; [ 0xb1 0xfa ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
JSR $1f63 ; [ 0x20 0x63 0x1f ]
DEX ; [ 0xca ]
BNE #$f0 ; [ 0xd0 0xf0 ]
LDA $f6 ; [ 0xa5 0xf6 ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
LDA $f7 ; [ 0xa5 0xf7 ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
INC $f8 ; [ 0xe6 0xf8 ]
BNE #$02 ; [ 0xd0 0x02 ]
INC $f9 ; [ 0xe6 0xf9 ]
JMP $1d48 ; [ 0x4c 0x48 0x1d ]
JSR $1fcc ; [ 0x20 0xcc 0x1f ]
JSR $1e2f ; [ 0x20 0x2f 0x1e ]
JSR $1e1e ; [ 0x20 0x1e 0x1e ]
JSR $1e9e ; [ 0x20 0x9e 0x1e ]
LDY #$00 ; [ 0xa0 0x00 ]
LDA ($fa),Y ; [ 0xb1 0xfa ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1e9e ; [ 0x20 0x9e 0x1e ]
JMP $1c64 ; [ 0x4c 0x64 0x1c ]
JSR $1f63 ; [ 0x20 0x63 0x1f ]
JMP $1dac ; [ 0x4c 0xac 0x1d ]
LDX $f2 ; [ 0xa6 0xf2 ]
TXS ; [ 0x9a ]
LDA $fb ; [ 0xa5 0xfb ]
PHA ; [ 0x48 ]
LDA $fa ; [ 0xa5 0xfa ]
PHA ; [ 0x48 ]
LDA $f1 ; [ 0xa5 0xf1 ]
PHA ; [ 0x48 ]
LDX $f5 ; [ 0xa6 0xf5 ]
LDY $f4 ; [ 0xa4 0xf4 ]
LDA $f3 ; [ 0xa5 0xf3 ]
RTI ; [ 0x40 ]
CMP #$20 ; [ 0xc9 0x20 ]
BEQ $ca ; [ 0xf0 0xca ]
CMP #$7f ; [ 0xc9 0x7f ]
BEQ $1b ; [ 0xf0 0x1b ]
CMP #$0d ; [ 0xc9 0x0d ]
BEQ $db ; [ 0xf0 0xdb ]
CMP #$0a ; [ 0xc9 0x0a ]
BEQ $1c ; [ 0xf0 0x1c ]
CMP #$2e ; [ 0xc9 0x2e ]
BEQ $26 ; [ 0xf0 0x26 ]
CMP #$47 ; [ 0xc9 0x47 ]
BEQ $d5 ; [ 0xf0 0xd5 ]
CMP #$51 ; [ 0xc9 0x51 ]
BEQ $0a ; [ 0xf0 0x0a ]
CMP #$4c ; [ 0xc9 0x4c ]
BEQ $09 ; [ 0xf0 0x09 ]
JMP $1c6a ; [ 0x4c 0x6a 0x1c ]
JMP $1c4f ; [ 0x4c 0x4f 0x1c ]
JMP $1d42 ; [ 0x4c 0x42 0x1d ]
JMP $1ce7 ; [ 0x4c 0xe7 0x1c ]
SEC ; [ 0x38 ]
LDA $fa ; [ 0xa5 0xfa ]
SBC #$01 ; [ 0xe9 0x01 ]
STA $fa ; [ 0x85 0xfa ]
BCS $02 ; [ 0xb0 0x02 ]
DEC $fb ; [ 0xc6 0xfb ]
JMP $1dac ; [ 0x4c 0xac 0x1d ]
LDY #$00 ; [ 0xa0 0x00 ]
LDA $f8 ; [ 0xa5 0xf8 ]
STA ($fa),Y ; [ 0x91 0xfa ]
JMP $1dc2 ; [ 0x4c 0xc2 0x1d ]
LDA $fb ; [ 0xa5 0xfb ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
LDA $fa ; [ 0xa5 0xfa ]
JSR $1e3b ; [ 0x20 0x3b 0x1e ]
JSR $1f91 ; [ 0x20 0x91 0x1f ]
RTS ; [ 0x60 ]
LDX #$07 ; [ 0xa2 0x07 ]
LDA $1fd5,X ; [ 0xbd 0xd5 0x1f ]
JSR $1ea0 ; [ 0x20 0xa0 0x1e ]
DEX ; [ 0xca ]
BPL #$f7 ; [ 0x10 0xf7 ]
RTS ; [ 0x60 ]
STA $fc ; [ 0x85 0xfc ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
JSR $1e4c ; [ 0x20 0x4c 0x1e ]
LDA $fc ; [ 0xa5 0xfc ]
JSR $1e4c ; [ 0x20 0x4c 0x1e ]
LDA $fc ; [ 0xa5 0xfc ]
RTS ; [ 0x60 ]
AND #$0f ; [ 0x29 0x0f ]
CMP #$0a ; [ 0xc9 0x0a ]
CLC ; [ 0x18 ]
BMI #$02 ; [ 0x30 0x02 ]
ADC #$07 ; [ 0x69 0x07 ]
ADC #$30 ; [ 0x69 0x30 ]
JMP $1ea0 ; [ 0x4c 0xa0 0x1e ]
STX $fd ; [ 0x86 0xfd ]
LDX #$08 ; [ 0xa2 0x08 ]
LDA #$01 ; [ 0xa9 0x01 ]
BIT $1740 ; [ 0x2c 0x40 0x17 ]
BNE #$22 ; [ 0xd0 0x22 ]
BMI #$f9 ; [ 0x30 0xf9 ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
JSR $1eeb ; [ 0x20 0xeb 0x1e ]
LDA $1740 ; [ 0xad 0x40 0x17 ]
AND #$80 ; [ 0x29 0x80 ]
LSR $fe ; [ 0x46 0xfe ]
ORA $fe ; [ 0x05 0xfe ]
STA $fe ; [ 0x85 0xfe ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
DEX ; [ 0xca ]
BNE #$ef ; [ 0xd0 0xef ]
JSR $1eeb ; [ 0x20 0xeb 0x1e ]
LDX $fd ; [ 0xa6 0xfd ]
LDA $fe ; [ 0xa5 0xfe ]
ROL ; [ 0x2a ]
LSR ; [ 0x4a ]
RTS ; [ 0x60 ]
LDX #$01 ; [ 0xa2 0x01 ]
STX $ff ; [ 0x86 0xff ]
LDX #$00 ; [ 0xa2 0x00 ]
STX $1741 ; [ 0x8e 0x41 0x17 ]
LDX #$3f ; [ 0xa2 0x3f ]
STX $1743 ; [ 0x8e 0x43 0x17 ]
LDX #$07 ; [ 0xa2 0x07 ]
STX $1742 ; [ 0x8e 0x42 0x17 ]
CLD ; [ 0xd8 ]
SEI ; [ 0x78 ]
RTS ; [ 0x60 ]
LDA #$20 ; [ 0xa9 0x20 ]
STA $fe ; [ 0x85 0xfe ]
STX $fd ; [ 0x86 0xfd ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
LDA $1742 ; [ 0xad 0x42 0x17 ]
AND #$fe ; [ 0x29 0xfe ]
STA $1742 ; [ 0x8d 0x42 0x17 ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
LDX #$08 ; [ 0xa2 0x08 ]
LDA $1742 ; [ 0xad 0x42 0x17 ]
AND #$fe ; [ 0x29 0xfe ]
LSR $fe ; [ 0x46 0xfe ]
ADC #$00 ; [ 0x69 0x00 ]
STA $1742 ; [ 0x8d 0x42 0x17 ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
DEX ; [ 0xca ]
BNE #$ee ; [ 0xd0 0xee ]
LDA $1742 ; [ 0xad 0x42 0x17 ]
ORA #$01 ; [ 0x09 0x01 ]
STA $1742 ; [ 0x8d 0x42 0x17 ]
JSR $1ed4 ; [ 0x20 0xd4 0x1e ]
LDX $fd ; [ 0xa6 0xfd ]
RTS ; [ 0x60 ]
LDA $17f3 ; [ 0xad 0xf3 0x17 ]
STA $17f4 ; [ 0x8d 0xf4 0x17 ]
LDA $17f2 ; [ 0xad 0xf2 0x17 ]
SEC ; [ 0x38 ]
SBC #$01 ; [ 0xe9 0x01 ]
BCS $03 ; [ 0xb0 0x03 ]
DEC $17f4 ; [ 0xce 0xf4 0x17 ]
LDY $17f4 ; [ 0xac 0xf4 0x17 ]
BPL #$f3 ; [ 0x10 0xf3 ]
RTS ; [ 0x60 ]
LDA $17f3 ; [ 0xad 0xf3 0x17 ]
STA $17f4 ; [ 0x8d 0xf4 0x17 ]
LDA $17f2 ; [ 0xad 0xf2 0x17 ]
LSR ; [ 0x4a ]
LSR $17f4 ; [ 0x4e 0xf4 0x17 ]
BCC $e3 ; [ 0x90 0xe3 ]
ORA #$80 ; [ 0x09 0x80 ]
BCS $e0 ; [ 0xb0 0xe0 ]
LDY #$03 ; [ 0xa0 0x03 ]
LDX #$01 ; [ 0xa2 0x01 ]
LDA #$ff ; [ 0xa9 0xff ]
STX $1742 ; [ 0x8e 0x42 0x17 ]
INX ; [ 0xe8 ]
INX ; [ 0xe8 ]
AND $1740 ; [ 0x2d 0x40 0x17 ]
DEY ; [ 0x88 ]
BNE #$f5 ; [ 0xd0 0xf5 ]
LDY #$07 ; [ 0xa0 0x07 ]
STY $1742 ; [ 0x8c 0x42 0x17 ]
ORA #$80 ; [ 0x09 0x80 ]
EOR #$ff ; [ 0x49 0xff ]
RTS ; [ 0x60 ]
LDY #$00 ; [ 0xa0 0x00 ]
LDA ($fa),Y ; [ 0xb1 0xfa ]
STA $f9 ; [ 0x85 0xf9 ]
LDA #$7f ; [ 0xa9 0x7f ]
STA $1741 ; [ 0x8d 0x41 0x17 ]
LDX #$09 ; [ 0xa2 0x09 ]
LDY #$03 ; [ 0xa0 0x03 ]
LDA $00f8,Y ; [ 0xb9 0xf8 0x00 ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
LSR ; [ 0x4a ]
JSR $1f48 ; [ 0x20 0x48 0x1f ]
LDA $00f8,Y ; [ 0xb9 0xf8 0x00 ]
AND #$0f ; [ 0x29 0x0f ]
JSR $1f48 ; [ 0x20 0x48 0x1f ]
DEY ; [ 0x88 ]
BNE #$eb ; [ 0xd0 0xeb ]
STX $1742 ; [ 0x8e 0x42 0x17 ]
LDA #$00 ; [ 0xa9 0x00 ]
STA $1741 ; [ 0x8d 0x41 0x17 ]
JMP $1efe ; [ 0x4c 0xfe 0x1e ]
STY $fc ; [ 0x84 0xfc ]
TAY ; [ 0xa8 ]
LDA $1fe7,Y ; [ 0xb9 0xe7 0x1f ]
LDY #$00 ; [ 0xa0 0x00 ]
STY $1740 ; [ 0x8c 0x40 0x17 ]
STX $1742 ; [ 0x8e 0x42 0x17 ]
STA $1740 ; [ 0x8d 0x40 0x17 ]
LDY #$7f ; [ 0xa0 0x7f ]
DEY ; [ 0x88 ]
BNE #$fd ; [ 0xd0 0xfd ]
INX ; [ 0xe8 ]
INX ; [ 0xe8 ]
LDY $fc ; [ 0xa4 0xfc ]
RTS ; [ 0x60 ]
INC $fa ; [ 0xe6 0xfa ]
BNE #$02 ; [ 0xd0 0x02 ]
INC $fb ; [ 0xe6 0xfb ]
RTS ; [ 0x60 ]
LDX #$21 ; [ 0xa2 0x21 ]
LDY #$01 ; [ 0xa0 0x01 ]
JSR $1f02 ; [ 0x20 0x02 0x1f ]
BNE #$07 ; [ 0xd0 0x07 ]
CPX #$27 ; [ 0xe0 0x27 ]
BNE #$f5 ; [ 0xd0 0xf5 ]
LDA #$15 ; [ 0xa9 0x15 ]
RTS ; [ 0x60 ]
LDY #$ff ; [ 0xa0 0xff ]
ASL ; [ 0x0a ]
BCS $03 ; [ 0xb0 0x03 ]
INY ; [ 0xc8 ]
BPL #$fa ; [ 0x10 0xfa ]
TXA ; [ 0x8a ]
AND #$0f ; [ 0x29 0x0f ]
LSR ; [ 0x4a ]
TAX ; [ 0xaa ]
TYA ; [ 0x98 ]
BPL #$03 ; [ 0x10 0x03 ]
CLC ; [ 0x18 ]
ADC #$07 ; [ 0x69 0x07 ]
DEX ; [ 0xca ]
BNE #$fa ; [ 0xd0 0xfa ]
RTS ; [ 0x60 ]
CLC ; [ 0x18 ]
ADC $f7 ; [ 0x65 0xf7 ]
STA $f7 ; [ 0x85 0xf7 ]
LDA $f6 ; [ 0xa5 0xf6 ]
ADC #$00 ; [ 0x69 0x00 ]
STA $f6 ; [ 0x85 0xf6 ]
RTS ; [ 0x60 ]
JSR $1e5a ; [ 0x20 0x5a 0x1e ]
JSR $1fac ; [ 0x20 0xac 0x1f ]
JSR $1e5a ; [ 0x20 0x5a 0x1e ]
JSR $1fac ; [ 0x20 0xac 0x1f ]
LDA $f8 ; [ 0xa5 0xf8 ]
RTS ; [ 0x60 ]
CMP #$30 ; [ 0xc9 0x30 ]
BMI #$1b ; [ 0x30 0x1b ]
CMP #$47 ; [ 0xc9 0x47 ]
BPL #$17 ; [ 0x10 0x17 ]
CMP #$40 ; [ 0xc9 0x40 ]
BMI #$03 ; [ 0x30 0x03 ]
CLC ; [ 0x18 ]
ADC #$09 ; [ 0x69 0x09 ]
ROL ; [ 0x2a ]
ROL ; [ 0x2a ]
ROL ; [ 0x2a ]
ROL ; [ 0x2a ]
LDY #$04 ; [ 0xa0 0x04 ]
ROL ; [ 0x2a ]
ROL $f8 ; [ 0x26 0xf8 ]
ROL $f9 ; [ 0x26 0xf9 ]
DEY ; [ 0x88 ]
BNE #$f8 ; [ 0xd0 0xf8 ]
LDA #$00 ; [ 0xa9 0x00 ]
RTS ; [ 0x60 ]
LDA $f8 ; [ 0xa5 0xf8 ]
STA $fa ; [ 0x85 0xfa ]
LDA $f9 ; [ 0xa5 0xf9 ]
STA $fb ; [ 0x85 0xfb ]
RTS ; [ 0x60 ]
BRK ; [ 0x00 ]
BRK ; [ 0x00 ]
BRK ; [ 0x00 ]
BRK ; [ 0x00 ]
BRK ; [ 0x00 ]
BRK ; [ 0x00 ]
ASL ; [ 0x0a ]
ORA $494d ; [ 0x0d 0x4d 0x49 ]
JSR $5213 ; [ 0x20 0x13 0x52 ]
EOR $20 ; [ 0x45 0x20 ]
STX $db ; [ 0x86 0xdb ]
INC $ed ; [ 0xe6 0xed ]
SBC $ff87,X ; [ 0xfd 0x87 0xff ]
LDA $f9de,Y ; [ 0xb9 0xde 0xf9 ]
SBC ($ff),Y ; [ 0xf1 0xff ]
Generated
+3129 -241
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -3,7 +3,8 @@ members = [
"core",
"cli",
"macroquad",
"beneater"
# "beneater"
"egui"
]
resolver="2"
+8 -8
View File
@@ -8,6 +8,7 @@ use core::mos6502cpu::cpu::Mos6502Cpu;
use core::periph::at28c256::At28C256;
use core::periph::hm62256::Hm62256;
use core::constants::constants_system::*;
use std::fs;
/// BenEater computer represents the 'Ben Eater' 6502 breadboard computer.
/// This was built along watching the video series where Ben builds a
@@ -20,20 +21,19 @@ pub struct BenEater {
}
impl BenEater {
pub fn new(rom: &[u8; SIZE_32KB]) -> BenEater {
}
// pub fn new(rom: &[u8; SIZE_32KB]) -> BenEater {
//
// }
}
#[macroquad::main("Ben Eaters PC")]
async fn main() {
println!("Taxation is Theft");
let rom_to_run = fs::read("resources/beneater/roms/ror.bin");
let mut pc = BenEater::new(&rom_to_run);
let mut backplane = Backplane::new();
// let rom_to_run = fs::read("resources/beneater/roms/ror.bin");
// let mut pc = BenEater::new(&rom_to_run);
//
// let mut backplane = Backplane::new();
// backplane.load_rom("resources/beneater/roms/ror.bin");
// let mut dm = DisplayMatrix::new(200.0, 50.0);
+5 -1
View File
@@ -8,6 +8,10 @@ fn main() {
let mut backplane = Backplane::new();
for i in 0..12 {
backplane.tick();
}
//backplane.load_rom();
println!("Backplane is live.");
@@ -16,7 +20,7 @@ fn main() {
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
println!("Set offset in rom...");
println!(
"VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ",
"VALUE AT OFFSET_RESET_VECTOR = 0x{:04x} ",
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
);
// println!("{:?}", new_program);
+4 -4
View File
@@ -1,9 +1,9 @@
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use crate::parts::via6522::VIA6522;
use core::constants::constants_system::*;
use core::mos6502cpu::cpu::Mos6502Cpu;
use core::mos6502cpu::Mos6502Cpu;
use core::periph::at28c256::At28C256;
use core::periph::rom_chip::RomChip;
use core::traits::rom_chip::RomChip;
use core::constants::constants_via6522::*;
/// Backplane
@@ -19,7 +19,7 @@ pub struct Backplane {
// pub for dev
pub cpu: Mos6502Cpu,
pub via: VIA6522,
pub memory: Box<[u8; SIZE_32KB]>,
pub memory: Box<[u8]>,
pub rom: At28C256,
data_bus: u8,
address_bus: u16
@@ -38,7 +38,7 @@ impl Backplane {
}
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
self.rom.program(to_load);
self.rom.program((*to_load).into());
}
pub fn tick(&mut self) {
+1 -1
View File
@@ -7,7 +7,7 @@ pub struct CpuDisplay {}
impl CpuDisplay {
pub fn render(cpu: &Mos6502Cpu, x_offset: f32, y_offset: f32) {
// get the data to display...
let (pc, a, x, y, address_bus, data_bus, microsteps_remaining, reset_vector, interrupt_vector) = cpu.dump_data();
let (pc, a, x, y, address_bus, data_bus, microsteps_remaining, reset_vector, interrupt_vector, nmi_vector) = cpu.dump_data();
// ...build the interface
Self::draw_square(x_offset, y_offset, x_offset + 300.0, y_offset + 85.0, BLACK);
+1
View File
@@ -201,6 +201,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_write_data() {
let mut lcd = HD44780::new();
lcd.set_data_bus(0x41); // 'A'
+4
View File
@@ -162,6 +162,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_timer1_write_and_tick() {
let mut via = VIA6522::new();
@@ -180,6 +181,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_timer2_write_and_tick() {
let mut via = VIA6522::new();
via.t2_enabled = true;
@@ -194,6 +196,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_interrupt_enable_disable() {
let mut via = VIA6522::new();
@@ -205,6 +208,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_clear_interrupt_flags() {
let mut via = VIA6522::new();
via.ifr = 0xFF;
+87 -18
View File
@@ -1,3 +1,8 @@
/*
64tass -a -o instructions.bin -b instructions.asm &&
cargo run --bin de6502 -- -v instructions.bin instructions_produced.asm &&
64tass -a -b instructions_produced.asm -o instructions_produced.bin
*/
use std::collections::HashMap;
use std::fs;
use std::fs::File;
@@ -15,7 +20,10 @@ struct CliOptions {
/// File to Decompile
input: PathBuf,
/// File to write
output: PathBuf
output: PathBuf,
/// Verbose output
#[arg(short, action = clap::ArgAction::Count)]
verbose: u8
}
#[derive(Debug)]
@@ -57,22 +65,23 @@ impl WorkingProgram {
}
fn decompile(data: &[u8]) -> Vec<(u16, DecompiledLine)> {
println!("Preparing to decompile {}b", data.len());
let mut current_data_position: u16 = 0;
fn parse_to_decompiled_lines(data: &[u8]) -> HashMap<u16, DecompiledLine> {
println!("PARSE GOT {}b", data.len());
let mut current_data_position = 0;
let mut lines: HashMap<u16, DecompiledLine> = HashMap::new();
while current_data_position < data.len() as u16 {
// read the next byte.
let next_byte = data[current_data_position as usize];
let mut bytes = vec![next_byte];
println!("Bytes = {bytes:?}");
let target_op = INSTRUCTION_TABLE[next_byte as usize].clone();
if let Some(top) = target_op {
// println!("Instruction {:?}/{:?} needs {:?} bytes.", top.operation, top.mode, top.length);
let num_bytes_to_load = top.length - 1;
println!("Need {num_bytes_to_load} more bytes.");
// println!("Need {num_bytes_to_load} more bytes.");
let mut formatted_asm = String::from(top.format_prefix);
let mut param = None;
if num_bytes_to_load == 1 {
@@ -83,7 +92,7 @@ fn decompile(data: &[u8]) -> Vec<(u16, DecompiledLine)> {
if num_bytes_to_load == 2 {
bytes.push(data[current_data_position as usize + 1]);
bytes.push(data[current_data_position as usize + 2]);
// 16 bit parameter.
// 16 bit parameter.
param = Some(((bytes[2] as u16) << 8) | bytes[1] as u16);
formatted_asm = format!("{}{:04x}{}", formatted_asm, param.unwrap(), top.format_postfix);
};
@@ -103,25 +112,45 @@ fn decompile(data: &[u8]) -> Vec<(u16, DecompiledLine)> {
current_data_position += 1;
}
}
lines
}
fn decompile(data: &Vec<u8>) -> Vec<(u16, DecompiledLine)> {
println!("Preparing to decompile {}b", data.len());
let mut current_data_position: u16 = 0;
let mut lines: HashMap<u16, DecompiledLine> = parse_to_decompiled_lines(data);
println!("Found {} instructions in pass 1. Adding labels for jumps.", lines.len());
//let targets = vec![];
for (index, line) in &lines {
if line.bytes[0] == ISA_OP_JMP_ABS {
// println!("ABS JUMP FOUND");
}
}
let mut items: Vec<_> = lines.into_iter().collect();
items.sort_by(|a, b| a.0.cmp(&b.0));
// loop through the lines for JSR and label the 'target' as SUB<index>
// let mut jump_targets = vec![];
for (line_index, working_line) in &mut items {
if working_line.is_jump() {
println!("There are {}b in bytes", working_line.bytes.len());
let target = read_word(&working_line.bytes[1..=2]);
println!("Found a jump at index {line_index} / 0x{line_index} with target of 0x{:04x}", target);;
// Derp -> this doesnt work.
// items[target as usize].1.label = Some("Label1".parse().unwrap());
}
}
// check the vectors to label those entrypoints.
// // check the vectors to label those entrypoints.
// let (mut main, mut nmi, mut irq) = (0, 0, 0);
// match data.len() {
// SIZE_32KB | SIZE_64KB => {
// main = read_word(&data[OFFSET_RESET_VECTORS..=OFFSET_RESET_VECTORS + 1]);
// nmi = read_word(&data[OFFSET_NMI_VECTORS..=OFFSET_NMI_VECTORS + 1]);
// irq = read_word(&data[OFFSET_INT_VECTORS..=OFFSET_INT_VECTORS]);
// }
// _ => {
// // dont know where to look for our offsets. :(
// }
// }
// -> main
// -> NMI
// -> IRQ
@@ -129,6 +158,37 @@ fn decompile(data: &[u8]) -> Vec<(u16, DecompiledLine)> {
items
}
/// read_word
///
/// Read a word from the provided data with first byte being
/// LSB
fn read_word(from: &[u8]) -> u16 {
(from[1] as u16) << 8 | from[0] as u16
}
/// read_word_swap
///
/// Read a word from the provided data with first byte being
/// MSB
fn read_word_swap(from: &[u8]) -> u16 {
(from[0] as u16) << 8 | from[1] as u16
}
/// format_bytes
///
/// formats data for stuff
fn format_bytes(from: &Vec<u8>) -> String {
let mut to_return = String::from("[");
for index in 0..from.len() {
to_return = format!("{} 0x{:02x}", to_return, from[index]);
}
to_return = format!("{} ]", to_return);
to_return
}
fn main() {
let opts = CliOptions::parse();
println!("Taxation is theft.");
@@ -147,8 +207,17 @@ fn main() {
// ...reap the decompiled code.
for (_, line) in &result {
let line =format!("{:width$}; {:?}", line.text,line.bytes, width=30 );
println!("{}", line);
writeln!(output_file, "{}", line).expect("cant write output file. you picked the red snapper.");
let formatted_bytes = format_bytes(&line.bytes);
let output_line =format!("{:width$}; {}", line.text, formatted_bytes, width=30 );
// do we need a label
if let Some(label) = &line.label {
println!("There is a label - {label}");
}
if opts.verbose > 0 {
println!("{}", output_line);
}
writeln!(output_file, "{}", output_line).expect("cant write output file. you picked the red snapper.");
}
println!("OPTS = {}", opts.verbose);
}
-2
View File
@@ -18,6 +18,4 @@ fn main() {
for (op, bytes) in instructions {
assert_eq!(Instruction::decode(bytes), Some(op));
}
// let instruction = Instruction::decode(&[0xea]);
// println!("NOP Decoded -> {:?}", instruction);
}
+26
View File
@@ -0,0 +1,26 @@
use core::computers::kim1::Kim1;
use core::constants::constants_system::*;
fn main() {
println!("Taxation is theft.");
let mut kim = Kim1::new();
let mut num_ticks = 0;
kim.running = true;
while kim.running {
kim.tick();
num_ticks += 1;
if num_ticks == MOS6502_RESET_CYCLE_COUNT {
println!("Got our 11 ticks. time to hotwire this pc.");
kim.running = true;
kim.dump();
}
if num_ticks == 15 {
kim.running = false;
kim.dump();
}
}
}
+48
View File
@@ -0,0 +1,48 @@
use core::computers::ram_rom::RamRomComputer;
use core::traits::backplane::Backplane;
use std::fs;
fn main() {
println!("Taxation is Theft");
// let opts = CliOptions::parse();
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
let bytes = match fs::read(path) {
Ok(bytes) => {
println!("Read {} bytes.", bytes.len());
bytes
},
Err(e) => {
eprintln!("FAIL to read rom.");
panic!("No rom no run.");
vec![]
}
};
let mut computer = RamRomComputer::new();
// Read byte from ROM 0x4000
println!("-- ");
computer.set_read_mode(true);
computer.set_address_bus(0x4020);
computer.tick();
println!("-- ");
// Data Bus contains value from ROM
let read_from_rom = computer.data_bus();
// Write byte to RAM 0x0000
computer.set_read_mode(false);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
// Read byte from RAM
computer.set_read_mode(true);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
let read_from_ram = computer.data_bus();
assert_eq!(read_from_rom, read_from_ram);
println!("Test passed. We read the same from ROM as we did from RAM - {} == {}", read_from_rom, read_from_ram);
}
-18
View File
@@ -1,18 +0,0 @@
use clap::Parser;
use core::computers::rom_only::backplane::Backplane;
#[derive(Parser)]
struct CliOptions {
offset: u16,
bytes: u16,
filename: String
}
fn main() {
println!("Taxation is theft");
let opts = CliOptions::parse();
let mut rom_only = Backplane::new();
rom_only.tick()
}
+6
View File
@@ -0,0 +1,6 @@
use core::computers::single_breadboard::SingleBreadboard;
fn main() {
let sb = SingleBreadboard::new();
}
-5
View File
@@ -1,5 +0,0 @@
use core::mos6502cpu::cpu::Mos6502Cpu;
fn main() {
let x = Mos6502Cpu::default();
}
+2
View File
@@ -0,0 +1,2 @@
mod ram_rom_tests;
mod rom_only_test;
+16
View File
@@ -0,0 +1,16 @@
use core::computers::ram_rom::RamRomComputer;
use core::traits::backplane::Backplane;
const RAM_START: u16 = 0x4000;
const ROM_START: u16 = 0x0000;
#[test]
fn ram_rom_thintick() {
let mut ramrom = RamRomComputer::new();
ramrom.tick2(0x0001, 1, 0x00);
println!("DataBus: {}", ramrom.data_bus());
ramrom.tick2(0x4001, 1,0xab);
println!("DataBus: {}", ramrom.data_bus());
ramrom.tick2(0x4001, 1,0x00);
println!("DataBus: {}", ramrom.data_bus());
}
+42
View File
@@ -0,0 +1,42 @@
use core::computers::rom_only::RomOnlyComputer;
use core::traits::backplane::Backplane;
#[test]
fn rom_only_widetick_test() {
let bytes = include_bytes!("/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin");
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
rom_only.tick2(0x05, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x05);
assert_eq!(rom_only.address_bus(), 0x05);
rom_only.tick2(0x07, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x07);
assert_eq!(rom_only.address_bus(), 0x07);
rom_only.tick2(0x09, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x09);
assert_eq!(rom_only.address_bus(), 0x09);
}
#[test]
fn rom_only_thintick_test() {
let bytes = include_bytes!("/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin");
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x05);
rom_only.tick();
assert_eq!(rom_only.data_bus(), 0x05);
assert_eq!(rom_only.address_bus(), 0x05);
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x07);
rom_only.tick();
assert_eq!(rom_only.data_bus(), 0x07);
assert_eq!(rom_only.address_bus(), 0x07);
}
+1
View File
@@ -5,3 +5,4 @@ edition = "2024"
[dependencies]
log = "0.4"
rand = "0.9.0"
once_cell = "0.1"
+52
View File
@@ -0,0 +1,52 @@
use crate::computers::beneater::BenEater;
use crate::traits::backplane::Backplane;
impl Backplane for BenEater {
fn data_bus(&self) -> u8 {
self.data_bus
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn read_mode(&self) -> bool {
self.read_mode
}
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn tick(&mut self) {
println!("Tick the system.");
self.tick_ram(self.address_bus, self.data_bus, true, true, true);
self.tick_rom(self.address_bus, true, true);
self.tick_via(self.address_bus, self.data_bus, true, true, self.read_mode, true, true);
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
println!("Ticking RAM");
0x00
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
println!("Ticking ROM");
0x00
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
println!("Ticking VIA 6522");
let (new_address, new_data) = self.via.tick(self.address_bus, self.data_bus, false, self.read_mode);
(new_data, false, false)
}
}
+22 -1
View File
@@ -1 +1,22 @@
pub mod beneater;
mod backplane;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6522::Mos6522;
/*
SBC Designed by Ben Eater
0x0000 -> 0x3fff -> RAM (16KB)
0x4000 -> 0x5fff -> UNUSED
0x6000 -> 0x600f -> VIA
0x6010 -> 0x7fff -> UNUSED
0x8000 -> 0xffff -> ROM (32KB)
*/
pub struct BenEater {
cpu: Mos6502Cpu,
via: Mos6522,
data_bus: u8,
address_bus: u16,
read_mode: bool
}
+23
View File
@@ -0,0 +1,23 @@
pub mod new;
pub mod tick;
pub mod reset;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad;
use crate::periph::mos6530::Mos6530;
/// Represents a KIM-1
///
///
pub struct Kim1 {
pub running: bool,
pub cpu: Mos6502Cpu,
rriot1: Mos6530,
rriot2: Mos6530,
ram: Hm62256,
pub(crate) keypad: Kim1Keypad,
address_bus: u16,
data_bus: u8,
cpu_read: bool
}
+31
View File
@@ -0,0 +1,31 @@
use crate::computers::kim1::Kim1;
use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad;
use crate::periph::mos6530::Mos6530;
impl Kim1 {
pub fn dump(&self) {
println!("DUMPING KIM-1 PC STATE");
self.cpu.dump();
self.rriot1.dump();
self.rriot2.dump();
self.keypad.dump();
}
pub fn new() -> Self {
let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-002_fillerbyte00-0x1c00.bin");
let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-003_fillerbyte00-0x1800.bin");
Self {
cpu: Default::default(),
rriot1: Mos6530::new(0x1700, 0x1780, 0x1800, &rriot1_rom),
rriot2: Mos6530::new(0x1740, 0x17C0, 0x1C00, &rriot2_rom),
ram: Hm62256::new(0x0000),
keypad: Kim1Keypad::new(),
address_bus: 0,
data_bus: 0,
cpu_read: false,
running: false
}
}
}
+18
View File
@@ -0,0 +1,18 @@
use crate::computers::kim1::Kim1;
use crate::periph::hm62256::Hm62256;
use crate::periph::mos6530::Mos6530;
impl Kim1 {
pub fn reset(&mut self) {
let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-002_fillerbyte00-0x1c00.bin");
let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-003_fillerbyte00-0x1800.bin");
self.cpu = Default::default();
self.rriot1 = Mos6530::new(0x1700, 0x1780, 0x1800, rriot1_rom.as_array().unwrap());
self.rriot2 = Mos6530::new(0x1740, 0x17c0, 0x1c00, rriot2_rom.as_array().unwrap());
self.ram = Hm62256::new(0x0000);
self.address_bus = 0x0000;
self.data_bus = 0x0000;
self.cpu_read = true;
self.cpu.pc = 0x0000;
}
}
+26
View File
@@ -0,0 +1,26 @@
use crate::computers::kim1::Kim1;
impl Kim1 {
pub fn tick(&mut self) {
println!("<- START KIM-1 Backplane Tick");
let (address_bus, data, rw) = self.cpu.tick2(self.address_bus, self.data_bus);
self.address_bus = address_bus;
self.data_bus = data;
self.cpu_read = rw;
// now tick the various items connected
self.rriot1.tick(self.address_bus, self.data_bus, false, self.cpu_read);
self.rriot2.tick(self.address_bus, self.data_bus, false, self.cpu_read);
self.ram.tick(self.address_bus, self.data_bus, self.cpu_read, true);
let (rr1_io, rr1_ram, rr1_rom) = self.rriot1.dump_data();
let (rr2_io, rr2_ram, rr2_rom) = self.rriot2.dump_data();
println!(" 0x0000 -> RAM / {}", self.ram.dump_data());
println!(" 0x1700 -> RRIOT 1 / 0x{rr1_io:04x}/0x{rr1_ram:04x}/0x{rr1_rom:04x}");
println!(" 0x1740 -> RRIOT 2 / 0x{rr2_io:04x}/0x{rr2_ram:04x}/0x{rr2_rom:04x}");
// display the memory map and device states
println!("-> FINISH KIM-1 Backplane Tick");
}
}
+4
View File
@@ -1,2 +1,6 @@
pub mod beneater;
pub mod rom_only;
pub mod kim1;
pub mod ram_rom;
pub mod tim1;
pub mod single_breadboard;
+71
View File
@@ -0,0 +1,71 @@
use log::debug;
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::traits::backplane::Backplane;
use crate::periph::hm62256::Hm62256;
impl Backplane for RamRomComputer {
fn data_bus(&self) -> u8 {
self.data_bus
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn read_mode(&self) -> bool {
self.read_mode
}
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode;
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value;
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value;
}
fn tick(&mut self) {
println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
// who are we talking to?
match self.address_bus {
0x0000..=0x3fff => {
// RAM
println!("ADDRESSING RAM");
let (ram_address_bus, ram_data_bus) = self.ram.tick(self.address_bus, self.data_bus, self.read_mode, true);
if self.read_mode {
self.data_bus = ram_data_bus;
}
},
0x4000..=0x7fff => {
// ROM
println!("ADDRESSING ROM");
let rom_data_bus = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
self.data_bus = rom_data_bus;
}
_ => {
// Out of range
}
}
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("Ticking ram with A${address:04x} D${data:02x} CS:{cs} OE:{oe} WE:{we}");
0
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
debug!("Ticking rom with A${address:04x} CS:{cs} OE:{oe}");
0
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("Ticking Via with A${address:04x} D${data:02x} cs0:{cs0} cs1:{cs1} rw:{rw} rs0:{rs0} rs1:{rs1}");
(0, false, false)
}
}
+15
View File
@@ -0,0 +1,15 @@
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
pub mod backplane;
pub mod program_rom;
pub mod new;
pub mod tick2;
pub struct RamRomComputer {
pub(crate) rom: At28C256,
pub(crate) ram: Hm62256,
pub(crate) data_bus: u8,
pub(crate) address_bus: u16,
pub(crate) read_mode: bool,
}
+17
View File
@@ -0,0 +1,17 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl RamRomComputer {
pub fn new() -> RamRomComputer {
let rom = At28C256::new(0x4000, 0x7fff, (0..255).collect());
RamRomComputer {
rom,
ram: Hm62256::default(),
data_bus: 0x00,
address_bus: 0x0000,
/// is the CPU reading from the 'other' device?
read_mode: true
}
}
}
+16
View File
@@ -0,0 +1,16 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl RamRomComputer {
pub fn program_rom(rom: Vec<u8>) -> RamRomComputer {
let new_rom = At28C256::new(0x0000, 0x3fff, rom);
RamRomComputer {
rom: new_rom,
ram: Hm62256::new(0x3fff),
data_bus: 0x00,
address_bus: 0x00,
read_mode: false,
}
}
}
+43
View File
@@ -0,0 +1,43 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::traits::backplane::Backplane;
struct ChipSignals {
cs: bool,
oe: bool,
we: bool
}
enum RomRamChips {
At28C256,
Hm62256
}
impl RamRomComputer {
pub fn tick2(&mut self, address: u16, control: u8, data: u8) -> (u8) {
println!("⏲RAM ROM Computer tick starting / {address:04x} {control:08b} {data:02x}");
// tick the parts
// map of memory
// 0x0000 -> 0x3fff -> RAM (HM62256)
// 0x4000 -> 0x7fff -> ROM (At28C256)
match address {
0x0000..=0x3fff => {
if self.read_mode {
println!("⏲__ROM BEING READ FROM");
let new_data = self.rom.signal_tick(address, data, true, true, true);
self.set_data_bus(new_data);
} else {
panic!("UNABLE TO WRITE TO ROM");
}
}
0x4000 ..=0x7fff => {
println!("⏲__DATA TARGETTING RRAAMM GETTING STORED ON DATA BUS");
}
_ => {}
};
let rom_data_bus = self.rom.signal_tick(self.address_bus ,self.data_bus, true ,true , true);
let (_, ram_data_bus) = self.ram.tick(address, data, control == 1, true);
0
}
}
+39 -23
View File
@@ -1,29 +1,45 @@
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB};
use crate::periph::hm62256::Hm62256;
use crate::periph::rom_chip::RomChip;
use log::debug;
use crate::computers::rom_only::RomOnlyComputer;
use crate::traits::backplane::Backplane;
pub struct Backplane {
rom: Hm62256,
data_bus: u8,
address_bus: u16
}
impl Backplane for RomOnlyComputer {
fn data_bus(&self) -> u8 { self.data_bus }
fn address_bus(&self) -> u16 { self.address_bus }
fn read_mode(&self) -> bool { self.read_mode }
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
impl Backplane {
pub fn new() -> Backplane {
Backplane::program(&[0x00; SIZE_32KB])
fn tick(&mut self) {
// println!("COMPUTER: Preparing to tick.");
// do are we being addressed?
// println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
// tick(self.address_bus, self.data_bus, self.read_mode);
self.set_address_bus(self.address_bus);
self.set_data_bus(new_data);
// println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
// println!("COMPUTER: Done ticking.");
}
pub fn program(rom: &[u8; SIZE_32KB]) -> Backplane {
Backplane {
rom: *Hm62256::program(rom),
address_bus: 0x0000,
data_bus: 0x00
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("This system has no ram. ROM only.");
0x00
}
pub fn tick(&mut self) {
println!("Preparing to tick.");
println!("Done ticking.");
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
let data = self.rom.signal_tick(address, self.data_bus, cs, oe, true);
data
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("This system has no VIA controllers. ROM only");
(0,false,false)
}
}
@@ -0,0 +1,12 @@
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn debug_memory(&self, start_offset: u16, end_offset: u16) -> Vec<u8> {
let mut data = vec![];
let size = end_offset - start_offset;
for index in 0..size {
println!("Index {index} for {}", index + start_offset);
}
data
}
}
+28
View File
@@ -1 +1,29 @@
use crate::periph::at28c256::At28C256;
use crate::traits::backplane::Backplane;
pub mod backplane;
pub mod new;
pub mod program;
pub mod debug_memory;
mod rom_chunks;
pub struct RomOnlyComputer {
pub rom: At28C256,
pub data_bus: u8,
pub address_bus: u16,
pub read_mode: bool,
}
impl RomOnlyComputer {
pub fn tick2(&mut self, address: u16, control: u8, data: u8) -> (u8) {
// tick the parts...
println!("WIDETICK: A:${address:04x} D:${data:02x} C:b{control:08b}");
self.address_bus = address;
self.data_bus = data;
let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
println!("\nNew Data : {new_data:02x}");
self.set_data_bus(new_data);
new_data
}
}
+12
View File
@@ -0,0 +1,12 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
impl RomOnlyComputer {
pub fn new() -> RomOnlyComputer {
let mut working = vec![0x00u8; SIZE_32KB];
for index in 0..SIZE_32KB {
working[index] = index as u8;
}
RomOnlyComputer::program(working)
}
}
+14
View File
@@ -0,0 +1,14 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl RomOnlyComputer {
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
RomOnlyComputer {
rom: At28C256::new(0x000, 0x3fff, rom),
address_bus: 0x0000,
data_bus: 0x00,
read_mode: true,
}
}
}
@@ -0,0 +1,8 @@
use std::slice::Chunks;
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn rom_chunks(&self, size: usize) -> Chunks<u8> {
self.rom.chunks(size)
}
}
@@ -0,0 +1,3 @@
Computer at
https://www.youtube.com/watch?v=s3t2QMukBRs
https://github.com/AndersBNielsen/6507SBC
@@ -0,0 +1,20 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::at28c256::At28C256;
use crate::periph::mos6532::Mos6532;
pub struct SingleBreadboard {
pub cpu: Mos6502Cpu,
pub ram: At28C256,
pub via: Mos6532
}
impl SingleBreadboard {
pub fn new() -> Self {
SingleBreadboard {
cpu: Mos6502Cpu::default(),
ram: At28C256::new(0xf000, 0xffff, vec![0x00; SIZE_32KB]),
via: Mos6532::new(0x0000, 0x0080)
}
}
}
+46
View File
@@ -0,0 +1,46 @@
use std::net::IpAddr::V4;
use log::debug;
use crate::computers::tim1::Tim1;
use crate::traits::backplane::Backplane;
impl Backplane for Tim1 {
fn data_bus(&self) -> u8 { self.data_bus }
fn address_bus(&self) -> u16 { self.address_bus }
fn read_mode(&self) -> bool { self.read_mode }
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn tick(&mut self) {
println!("Starting tick for TIM-1");
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("No dedicated RAM. Its in the VIA");
0x00
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
debug!("No dedicated ROM. Its in the VIA");
0x00
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("Starting VIA Tick");
self.pia.tick(address, data, false, self.read_mode);
// is this for the ROM?
// is this for the RAM?
// is this for the Interrupts?
// is this for the Timers?
(0x00, false, false)
}
}
+13
View File
@@ -0,0 +1,13 @@
mod backplane;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6530::Mos6530;
pub struct Tim1 {
cpu: Mos6502Cpu,
pia: Mos6530,
read_mode: bool,
data_bus: u8,
address_bus: u16
}
+23
View File
@@ -0,0 +1,23 @@
pub const MOS6530_DRA: u8 = 0x00;
pub const MOS6530_DDRA: u8 = 0x01;
pub const MOS6530_DRB: u8 = 0x02;
pub const MOS6530_DDRB: u8 = 0x03;
/*
0 X Data Register A
1 X Data Direction Register A
2 X Data Register B
3 X Data Direction Register B
4 0 Count down from value, divide by 1, disable IRQ 1 ???
5 0 Count down from value, divide by 8, disable IRQ 1 ???
6 0 Count down from value, divide by 64, disable IRQ 1 Read current counter value, disable IRQ
7 0 Count down from value, divide by 1024, disable IRQ 1 Read counter status, bit7 = 1 means counter past zero
8 X Data Register A (mirror ?)
9 X Data Direction Register A (mirror ?)
A X Data Register B (mirror ?)
B X Data Direction Register B (mirror ?)
C 0 Count down from value, divide by 1, enable IRQ 1 ???
D 0 Count down from value, divide by 8, enable IRQ 1 ???
E 0 Count down from value, divide by 64, enable IRQ 1 Read current counter value, enable IRQ
F 0 Count down from value, divide by 1024, enable IRQ 1 Read counter status, bit7 = 1 means counter past zero
*/
+9
View File
@@ -2,6 +2,15 @@ pub const SIZE_1KB: usize = 1024;
pub const SIZE_32KB: usize = SIZE_1KB * 32;
pub const SIZE_64KB: usize = SIZE_1KB * 64;
// S Suffixed constants are for indexing slices
pub const OFFSET_NMI_VECTOR: u16 = 0xfffa;
pub const OFFSET_NMI_VECTORS: usize = 0xfffa;
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
pub const OFFSET_RESET_VECTORS: usize = 0xffff;
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
pub const OFFSET_INT_VECTORS: usize = 0xfffe;
// 7 cycles for internal reset
// 6 to read the vectors from RAM
pub const MOS6502_RESET_CYCLE_COUNT: u16 = 8;
+7
View File
@@ -0,0 +1,7 @@
use std::borrow::ToOwned;
use once_cell::unsync::Lazy;
pub const TEST_RESOURCES_ROOT: &str = "/home/tmerritt/Projects/resources/test";
pub const TEST_PERIPH_ROOT: &str = "/home/tmerritt/Projects/resources/test/periph";
pub const TEST_PERIPH_AT28C256_ROOT: &str = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256";
-1
View File
@@ -17,4 +17,3 @@ pub const VIA6522_ACR: u8 = 0b1100;
pub const VIA6522_PCR: u8 = 0b1101;
pub const VIA6522_IFR: u8 = 0b1110;
pub const VIA6522_IER: u8 = 0b1111;
+2
View File
@@ -2,3 +2,5 @@ pub mod constants_isa_op;
pub mod constants_isa_stub;
pub mod constants_system;
pub mod constants_via6522;
pub mod constants_mos6530;
pub mod constants_test;
+2 -1263
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -1,3 +1,5 @@
#![feature(slice_as_array)]
pub mod computers;
pub mod address_mode;
pub mod constants;
@@ -9,3 +11,4 @@ pub mod op_info;
pub mod operand;
pub mod operation;
pub mod periph;
pub mod traits;
+27
View File
@@ -0,0 +1,27 @@
use crate::mos6502cpu::Mos6502Cpu;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6502Cpu {
fn min_offset(&self) -> u16 { 0 }
fn max_offset(&self) -> u16 {
0x7fff
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value;
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value;
}
}
+77 -110
View File
@@ -9,87 +9,17 @@ use crate::op_info::OpInfo;
use crate::operand::Operand;
use crate::operation::Operation;
use log::trace;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::*;
pub struct Mos6502Cpu {
pub(crate) memory: [u8; SIZE_64KB],
/// accumulator
pub(crate) a: u8,
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
pub(crate) ir: Instruction, // Instruction Register
pub(crate) oi: OpInfo,
pub(crate) has_reset: bool,
pub(crate) iv: u16, // Interrupt Vector
pub(crate) cycle_carry: u16, // Value to hold between microsteps
pub(crate) ir_bytes: [u8; 4],
/// CPU Read signal
pub read_signal: bool,
pub(crate) reset_vector: u16,
pub(crate) int_vector: u16
enum Mos6502Registers {
A,
X,
Y
}
impl Mos6502Cpu {
/// set_data_bus
///
/// Sets data on the data bus.
/// Used when CPU is in "R" mode
pub fn set_data_bus(&mut self, to_set: u8) {
self.data_bus = to_set;
}
}
impl Default for Mos6502Cpu {
fn default() -> Self {
let mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000
};
working.reset_cpu();
working
}
}
impl Mos6502Cpu {
pub fn address_bus(&self) -> u16 {
self.address_bus
}
pub fn data_bus(&self) -> u8 {
self.data_bus
}
//
// fn read_word(&self, offset: &u16) -> u16 {
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
@@ -102,6 +32,22 @@ impl Mos6502Cpu {
// result
// }
pub fn peek_register(&self, register_to_peek: Mos6502Registers) -> u8 {
match register_to_peek {
Mos6502Registers::A => self.a,
Mos6502Registers::X => self.x,
Mos6502Registers::Y => self.y
}
}
pub fn poke_register(&mut self, register_to_poke: Mos6502Registers, new_value: u8) {
match register_to_poke {
Mos6502Registers::A => self.a = new_value,
Mos6502Registers::X => self.x = new_value,
Mos6502Registers::Y => self.y = new_value
}
}
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
self.flags.flag(flag_to_read)
}
@@ -113,42 +59,15 @@ impl Mos6502Cpu {
}
}
pub fn peek(&self, offset: u16) -> u8 {
pub fn peek_memory(&self, offset: u16) -> u8 {
self.memory[offset as usize]
}
pub fn poke(&mut self, offset: u16, value: u8) {
pub fn poke_memory(&mut self, offset: u16, value: u8) {
println!("Setting memory at {offset:04x} to {value:02x}");
self.memory[offset as usize] = value
}
pub fn peek_a(&self) -> u8 {
println!("Readding register A => 0x{:02x}", self.a);
self.a
}
pub fn poke_a(&mut self, new_a: u8) {
println!("Updating register A from [{}] to [{}]", self.a, new_a);
self.a = new_a;
}
pub fn peek_x(&self) -> u8 {
println!("Readding register X => 0x{}", self.x);
self.x
}
pub fn poke_x(&mut self, new_x: u8) {
println!("Updating register X from [{}] to [{}]", self.x, new_x);
self.x = new_x
}
pub fn peek_y(&self) -> u8 {
self.y
}
pub fn poke_y(&mut self, new_y: u8) {
self.y = new_y
}
fn advance_pc(&mut self, how_far: u16) {
self.pc += how_far;
}
@@ -160,6 +79,47 @@ impl Mos6502Cpu {
/// Ticks the CPU
pub fn tick(&mut self) {
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
match self.tick_stage {
LoadingInstruction => {
println!("Loading instruction from data bus -> {}", self.data_bus);
let instruction = INSTRUCTION_TABLE[self.data_bus as usize].clone();
if let Some(inst) = instruction {
println!("DECODED INSTRUCTION [{:?}]/[{:?}]", inst.operation, inst.mode);
match inst.mode {
AddressMode::Absolute | AddressMode::AbsoluteX | AddressMode::AbsoluteY => {
println!("NEED TO LOAD a 16bit VALUE FOR INSTRUCTION");
self.tick_stage = Loading16BitParameter1;
}
AddressMode::Immediate => {
println!("LOADING A 8BIT VALUE FOR INSTRUCTION");
self.tick_stage = Loading8BitParameter;
}
_ => {}
}
} else {
println!("INVALID DECODE OF [${:02x}", self.data_bus);
}
}
Loading8BitParameter => {
println!("Loading parameter for 8bit ");
},
Loading16BitParameter1 => {
println!("Loading high bits of parameter");
},
Loading16BitParameter2 => {
println!("Loading low bits of parameter");
},
Stall(length) => {
println!("PREPARING TO STALL FOR {} CYCLES", length);
},
Waiting => {
println!("CPU IS WAITING.");
}
}
if self.microcode_step == 0 {
println!("OUT OF MICROSTEPS. Decoding the next instruction");
let offset = self.pc as usize;
@@ -273,7 +233,7 @@ impl Mos6502Cpu {
Operation::DEX => {
if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_sub(1);
self.poke_x(new_x);
self.poke_register(Mos6502Registers::X, new_x);
self.poke_flag(Carry, new_carry);
}
}
@@ -287,7 +247,7 @@ impl Mos6502Cpu {
Operation::INX => {
if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_add(1);
self.poke_x(new_x);
self.poke_register(Mos6502Registers::X, new_x);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
@@ -296,7 +256,7 @@ impl Mos6502Cpu {
Operation::INY => {
if self.microcode_step == 1 {
let (new_y, new_carry) = self.y.overflowing_add(1);
self.poke_y(new_y);
self.poke_register(Mos6502Registers::Y, new_y);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
@@ -478,7 +438,7 @@ impl Mos6502Cpu {
}
}
}
/*
#[cfg(test)]
mod test {
use super::*;
@@ -489,6 +449,12 @@ mod test {
fn clc() {
// setup the CPU for our test
let mut cpu = Mos6502Cpu::default();
// tick through the reset cycle
while !cpu.has_reset {
cpu.tick();
}
println!("DONE RESET TICKS");
cpu.flags.set_flag(Carry);
// Load our 'test program'
cpu.memory[0x6000] = ISA_OP_CLC;
@@ -715,3 +681,4 @@ mod test {
assert_eq!(cpu.memory[0xab], 0b1010_1010);;
}
}
*/
+9 -5
View File
@@ -1,11 +1,11 @@
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::mos6502cpu::Mos6502Cpu;
impl Mos6502Cpu {
/// dump_data
///
/// returns
/// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step
pub fn dump_data(&self) -> (u16, u8, u8, u8, u16, u8, u8, u16, u16) {
pub fn dump_data(&self) -> (u16, u8, u8, u8, u16, u8, u8, u16, u16, u16) {
(
self.pc,
self.a,
@@ -15,13 +15,14 @@ impl Mos6502Cpu {
self.data_bus,
self.microcode_step,
self.reset_vector,
self.int_vector
self.int_vector,
self.nmi_vector
)
}
pub fn dump(&self) {
println!(
"CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}",
"CPU State: PC: ${:04x} / A: ${:02x} / X: ${:02x} / Y: ${:02x} / ADDRESS: ${:04x} / DATA: ${:02x} / MICROSTEPS: {:02} / S: {} / NMI: ${:04x} / RST: ${:04x} / INT: ${:04x}",
self.pc,
self.a,
self.x,
@@ -29,7 +30,10 @@ impl Mos6502Cpu {
self.address_bus,
self.data_bus,
self.microcode_step,
self.flags.dump()
self.flags.dump(),
self.nmi_vector,
self.reset_vector,
self.int_vector
);
}
}
+43
View File
@@ -0,0 +1,43 @@
use crate::address_mode::AddressMode;
use crate::constants::constants_isa_op::ISA_OP_NOP;
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::instruction_table::INSTRUCTION_TABLE;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::LoadingInstruction;
use crate::operand::Operand;
use crate::operation::Operation;
impl Default for Mos6502Cpu {
fn default() -> Self {
let mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000,
nmi_vector: 0x0000,
tick_stage: LoadingInstruction
};
working.reset_cpu();
working
}
}
+41 -3
View File
@@ -1,6 +1,44 @@
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502flags::Mos6502Flags;
use crate::op_info::OpInfo;
pub mod cpu;
pub mod new;
pub mod tick2;
mod dbg;
mod tick_stages;
pub mod dbg;
pub mod tick_stages;
pub mod default;
pub mod bus_device;
pub struct Mos6502Cpu {
pub(crate) memory: [u8; SIZE_64KB],
/// accumulator
pub(crate) a: u8,
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
pub(crate) ir: Instruction, // Instruction Register
pub(crate) oi: OpInfo,
pub(crate) has_reset: bool,
pub(crate) iv: u16, // Interrupt Vector
pub(crate) cycle_carry: u16, // Value to hold between microsteps
pub(crate) ir_bytes: [u8; 4],
/// CPU Read signal
pub read_signal: bool,
pub(crate) reset_vector: u16,
pub(crate) int_vector: u16,
pub(crate) nmi_vector: u16,
pub tick_stage: Mos6502TickStates
}
+5 -7
View File
@@ -1,5 +1,5 @@
use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB};
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::constants::constants_system::{MOS6502_RESET_CYCLE_COUNT, OFFSET_RESET_VECTOR, SIZE_64KB};
use crate::mos6502cpu::Mos6502Cpu;
impl Mos6502Cpu {
pub fn new() -> Mos6502Cpu {
@@ -13,14 +13,12 @@ impl Mos6502Cpu {
working
}
pub(crate) fn reset_cpu(&mut self) {
self.microcode_step = 7 + 4;
self.microcode_step = MOS6502_RESET_CYCLE_COUNT as u8;
// self = &mut Mos6502Cpu::default();
println!("Should tick 7 times, then 4 cycles to read the reset and int vectors.");
println!("Should tick 7 times, then 6 cycles to read the reset and int vectors.");
// read the value at 0xfffa 0xfffb for our NMI vector.
// read the value at 0xfffc 0xfffd for our reset vector.
// read the value at 0xfffe 0xffff for our int vector
}
}
+72 -44
View File
@@ -1,7 +1,69 @@
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::mos6502cpu::Mos6502Cpu;
enum Mos6502ResetSteps {
/// there are 6 of these
DummyRead(u8),
ReadRstVectorLow,
ReadRstVectorHigh,
ReadPcLow,
ReadPcHigh
}
impl Mos6502Cpu {
fn reset_step(&mut self, address_bus: u16, data_bus: u8, read: bool) -> (u16, u8, bool) {
println!("Reset microstep {}", self.microcode_step);
// we need to do the reset steps
// reduce the number of remaining microsteps
self.read_signal = true;
match self.microcode_step {
6 => {
// NMI High byte
}
5 => {
// NMI low byte
}
4 => {
// read first byte of reset vector
self.address_bus = OFFSET_RESET_VECTOR;
}
3 => {
// at this point data holds the upper byte of our reset vector
self.reset_vector = (data_bus as u16) << 8;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// read secondd byte of reset vector
self.address_bus = OFFSET_RESET_VECTOR + 1;
}
2 => {
self.reset_vector |= data_bus as u16;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// read first byte of interrupt vector
self.address_bus = OFFSET_INT_VECTOR;
}
1 => {
// read second byte of interrupt vector
self.address_bus = OFFSET_INT_VECTOR + 1;
}
0 => {
self.int_vector |= data_bus as u16;
println!("Loaded interrupt vector of 0x{:04x}", self.int_vector);
self.pc = self.reset_vector;
println!("Set PC to Reset Vector. Giddy-up!");
println!("START HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
// the KIM-1 uses 0x0000 for its initial PC
self.pc = 0x0000;
println!("END HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
self.has_reset = true;
}
_ => {
}
}
if self.microcode_step > 0 {
self.microcode_step -= 1;
}
(address_bus, data_bus, read)
}
/// AccurateTick
///
/// In: address_bus > Address of data operationm
@@ -14,50 +76,16 @@ impl Mos6502Cpu {
/// read_bus > lets rest of the computer know if the CPU is reading from the address
/// provided or if we are writing to the address
pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) {
if self.has_reset {
// we have completed the reset cycle
if self.read_signal {
// we should see new data in the data_bus for us
let read_data = data_bus;
} else {
// we are writing to the bus.
}
println!("STARTING TICK2");
if !self.has_reset { return self.reset_step(address_bus, data_bus, self.read_signal) }
// we have completed the reset cycle
if self.read_signal {
// we should see new data in the data_bus for us
let read_data = data_bus;
println!("READ 0x{read_data:02x} from data bus.");
self.data_bus = read_data;
} else {
println!("Reset microstep {}", self.microcode_step);
// we need to do the reset steps
// reduce the number of remaining microsteps
self.read_signal = true;
match self.microcode_step {
4 => {
// read first byte of reset vector
self.address_bus = OFFSET_RESET_VECTOR;
}
3 => {
// at this point data holds the upper byte of our reset vector
self.reset_vector = (data_bus as u16) << 8;
// read secondd byte of reset vector
self.address_bus = OFFSET_RESET_VECTOR + 1;
}
2 => {
self.reset_vector |= data_bus as u16;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// read first byte of interrupt vector
self.address_bus = OFFSET_INT_VECTOR;
}
1 => {
// read second byte of interrupt vector
self.address_bus = OFFSET_INT_VECTOR + 1;
}
0 => {
self.int_vector |= data_bus as u16;
println!("Loaded interrupt vector of 0x{:04x}", self.int_vector);
self.pc = self.reset_vector;
println!("Set PC to Reset Vector. Giddy-up!");
}
_ => {
}
}
self.microcode_step -= 1;
// we are writing to the bus.
}
(self.address_bus, self.data_bus, self.read_signal)
}
+3 -3
View File
@@ -3,7 +3,7 @@
///
/// The set of what a tick can be doing
///
enum Mos6502TickStates {
pub enum Mos6502TickStates {
/// Loading the first byte into the IR
LoadingInstruction,
/// Loading an 8 bit parameter
@@ -14,6 +14,6 @@ enum Mos6502TickStates {
Loading16BitParameter2,
/// Stalling for accurate emulation
Stall(u8),
/// Completed the instruction
Complete
/// Waiting for the next instruction
Waiting
}
+9 -38
View File
@@ -1,6 +1,4 @@
use crate::mos6502flags::Mos6502Flag::{
Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero,
};
use crate::mos6502flags::Mos6502Flag::*;
pub const BIT_NEGATIVE: u8 = 7;
pub const BIT_OVERFLOW: u8 = 6;
@@ -68,13 +66,14 @@ impl Mos6502Flag {
#[derive(Default, PartialEq, Debug)]
pub struct Mos6502Flags {
carry: bool,
zero: bool,
interrupt: bool,
decimal: bool,
break_flag: bool,
overflow: bool,
negative: bool,
// TODO: This is pub for tests. shouldn't be that way
pub carry: bool,
pub zero: bool,
pub interrupt: bool,
pub decimal: bool,
pub break_flag: bool,
pub overflow: bool,
pub negative: bool,
}
impl Mos6502Flags {
@@ -197,31 +196,3 @@ impl Mos6502Flags {
(src >> pos) & 1 != 0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
}
#[test]
fn sanity() {
let f = Mos6502Flags::default();
let magic_byte = 0b1110_1101;
let magic_flags = Mos6502Flags {
carry: true,
zero: false,
interrupt: true,
decimal: true,
break_flag: false,
overflow: true,
negative: true,
};
assert_eq!(magic_flags, Mos6502Flags::from_byte(magic_byte));
}
}
+9
View File
@@ -0,0 +1,9 @@
Peripherals
At28C256 - 256 byte static ram
Hm682256 - 256 byte ROM
Kim1_Keypad - Keypad for KIM-1 Computer
mos6520 - Peripheral Adapter
mos6522 - Versatile Interface Adapter (6520++)
mos6530 - RRIOT (Ram, Rom, Input, Output, Timers)
+8
View File
@@ -0,0 +1,8 @@
use std::slice::Chunks;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn chunks(&self, size: usize) -> Chunks<u8> {
self.data.chunks(size)
}
}
+28
View File
@@ -0,0 +1,28 @@
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
impl BusDevice for At28C256 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+17
View File
@@ -0,0 +1,17 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
use crate::constants::constants_test::*;
impl At28C256 {
/// checksum
///
/// calculates and returns the checksum for the loaded binary.
/// files with all zero will calculate to zero
pub fn checksum(&self) -> u8 {
At28C256::checksum_static(&self.data[..])
}
pub fn checksum_static(data: &[u8]) -> u8 {
data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b))
}
}
+8
View File
@@ -0,0 +1,8 @@
use crate::periph::at28c256::At28C256;
use crate::traits::bus_control_byte::BusControlByte;
const CTRL_CS: u8 = 0b0000_0001;
const CTRL_WE: u8 = 0b0000_0010;
const CTRL_OE: u8 = 0b0000_0100;
pub struct At28c256Control {}
+10 -11
View File
@@ -9,16 +9,15 @@ impl Default for At28C256 {
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice
.try_into()
.expect("Failed to convert Vec to boxed array");
At28C256 { data: boxed_array }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
At28C256 {
data: boxed_array,
address_bus: 0x0000,
data_bus: 0x00,
offset: 0x0000,
max_offset: 0x3fff,
cs: false,
oe: false,
we: false
}
}
}
+15
View File
@@ -0,0 +1,15 @@
use crate::periph::at28c256::At28C256;
pub struct At28C256State {
offset: u16,
max_offset: u16
}
impl At28C256 {
pub fn dump(&self) -> At28C256State {
At28C256State {
offset: self.offset,
max_offset: self.max_offset
}
}
}
+16
View File
@@ -0,0 +1,16 @@
use log::debug;
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip for At28C256 {
/// read
///
/// Reads a byte from memory.
/// Returns a 0x00 if there is no data at that location but is still in ROM address range
fn read(&self, offset: &u16) -> u8 {
let effective = self.internal_address(*offset);
debug!("STARTING READ FROM At28C256 ${:04x} | ${:04x} / ${effective:04x} | ${:04x}", self.offset, offset, self.max_offset);
if effective >= self.data.len() as u16 { 0x00 } else { self.data[effective as usize] }
}
}
+21 -32
View File
@@ -1,42 +1,31 @@
pub mod default;
pub mod rom_chip;
pub mod tick;
mod new;
mod program;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::rom_chip::RomChip;
use std::io::Read;
pub mod new;
pub mod program;
pub mod dump;
pub mod checksum;
pub mod blocks;
pub mod control;
pub mod signal_tick;
pub mod memory_chip;
pub mod bus_device;
/// At28C256
///
/// Represents a single At28C256 Chip
/// Represents a single At28C256 EEPROM Chip
///
/// 256kbit storage
/// 32kbyte storage
pub struct At28C256 {
data: Box<[u8; SIZE_32KB]>,
}
#[cfg(test)]
mod test {
use super::*;
use crate::constants::constants_system::SIZE_1KB;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn programmed_data_reads_back_same() {
let mut data = At28C256::default();
for i in 0..SIZE_32KB {
data.data[i] = 0xea;
}
for offset in 0..SIZE_32KB {
if offset.is_multiple_of(SIZE_1KB) {};
assert_eq!(0xea, data.read(&(offset as u16)));
}
}
// Logical parts
data_bus: u8,
address_bus: u16,
pub data: Box<[u8]>,
// where in the computer memory map do we live?
offset: u16,
max_offset: u16,
// Physical Parts
cs: bool,
we: bool,
oe: bool
}
+11 -2
View File
@@ -2,9 +2,18 @@ use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn new(data: &[u8; SIZE_32KB]) -> Self {
pub fn new(offset: u16, max_offset: u16, data: Vec<u8>) -> Self {
println!("NEW At28C256 with checksum ${:02x}", At28C256::checksum_static(&data[..]));
At28C256 {
data: (*data).into()
data: data.into_boxed_slice(),
address_bus: 0x0000,
data_bus: 0x00,
offset,
max_offset,
cs: false,
oe: false,
we: false
}
}
}
+3 -2
View File
@@ -2,9 +2,10 @@ use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) {
pub fn program(&mut self, new_program: Box<[u8]>) {
// panic!("FAIL. Cant program the chip.");
// println!("PROGRAMMING {:?}", new_program);
self.data = Box::new(*new_program);
self.data = new_program;
}
}
+11 -19
View File
@@ -1,26 +1,18 @@
use log::debug;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
use crate::periph::rom_chip::RomChip;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
impl RomChip for At28C256 {
fn read(&self, offset: &u16) -> u8 {
self.data[*offset as usize]
}
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
/// program
///
/// Writes new data to the memory chip
fn program(new_data: &[u8]) -> Box<At28C256> {
println!("Writing new chip.");
let mut working = At28C256::default();
working.data = Box::new(*new_data);
working.into()
working.data = new_data.to_vec().into_boxed_slice();
Box::new(working)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
const CHIP_SIZE: usize = SIZE_32KB ;
impl At28C256 {
/// Tick the ROM
/// address_bus
/// data_bus
/// CS -> Chip Select
/// OE -> Output Enable
/// WE -> Write Enable
pub fn signal_tick(&mut self, address_bus: u16, data_bus: u8, cs: bool, oe: bool, we: bool) -> (u8) {
// if we aren't selected and we aren't able to write to the bus...
if !cs || !we || !oe { return data_bus };
// if we aren't being addressed directly
if !(address_bus <= self.max_offset && address_bus >= self.offset) {
return data_bus
};
let internal_address = address_bus - self.offset;
let result = if internal_address < CHIP_SIZE as u16 {
self.data[internal_address as usize]
} else {
data_bus
};
println!("At28C256 EADDR: ${address_bus:04x} IADDR: ${internal_address:04x} = {result:02x}");
result
}
}
-33
View File
@@ -1,33 +0,0 @@
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl At28C256 {
fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
if read_mode {
panic!("UNABLE TO WRITE TO ROM");
} else {
// has to be read mode. its a rom.
return (address_bus, data_bus)
}
(address_bus, self.data[address_bus as usize])
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn write_to_memory_read_back_works_at_0() {
let mut rom = At28C256::default();
rom.tick(0x0000, 0xab, false);
let (_, new_data) = rom.tick(0x0000, 0x00, true);
assert_eq!(new_data, 0xab);
}
}
+29
View File
@@ -0,0 +1,29 @@
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Hm62256 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+8
View File
@@ -0,0 +1,8 @@
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_control_byte::BusControlByte;
const CTRL_CS: u8 = 0b0000_0001;
const CTRL_WE: u8 = 0b0000_0010;
const CTRL_OE: u8 = 0b0000_0100;
pub struct Hm62256Control;
+21
View File
@@ -0,0 +1,21 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
impl Default for Hm62256 {
fn default() -> Self {
let vec = vec![0x00; SIZE_32KB];
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
let boxed_array: Box<[u8; SIZE_32KB]> =
boxed_slice.try_into().expect("Unable to box the ram");
Hm62256 {
offset: 0x0000,
max_offset: 0x2000,
data: boxed_array,
address_bus: 0x0000,
data_bus: 0x00,
cs: false,
oe: false,
we: false
}
}
}
+17
View File
@@ -0,0 +1,17 @@
use crate::periph::hm62256::Hm62256;
pub struct Hm62256State {
pub offset: u16
}
impl Hm62256 {
pub fn dump(&self) -> Hm62256State {
Hm62256State {
offset: self.offset
}
}
pub fn dump_data(&self) -> (u16) {
self.offset
}
}
+11
View File
@@ -0,0 +1,11 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip for Hm62256 {
fn read(&self, offset: &u16) -> u8 {
// loops memory around past 32k
let effective = *offset as i32 % SIZE_32KB as i32;
self.data[effective as usize]
}
}
+22 -63
View File
@@ -3,72 +3,31 @@
pub mod ramchip;
pub mod romchip;
pub mod tick;
pub mod default;
pub mod new;
pub mod dump;
mod control;
mod bus_device;
mod memory_chip;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::ram_chip::RamChip;
use crate::periph::rom_chip::RomChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
use log::debug;
/// Hitachi Semiconductor
/// 8 Bit High Speed Static Ram
/// 32KByte
pub struct Hm62256 {
pub(crate) base_offset: u16,
pub(crate) offset: u16,
pub(crate) max_offset: u16,
pub(crate) data: Box<[u8]>,
}
impl Default for Hm62256 {
fn default() -> Self {
let vec = vec![0x00; SIZE_32KB];
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
let boxed_array: Box<[u8; SIZE_32KB]> =
boxed_slice.try_into().expect("Unable to box the ram");
Hm62256 {
base_offset: 0x0000,
data: boxed_array,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use rand::random;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn written_data_comes_back() {
let mut ram = Hm62256::default();
// 100,000 random read/writes to ram that all read back right
for _ in 0..100_000 {
let mut offset: u16 = random();
println!("Size = {SIZE_32KB}");
let value: u8 = random();
println!("Wrote [{value:02x}] to [{offset:04x}]");
ram.write(&offset, &value);
assert_eq!(ram.read(&offset), value)
}
}
#[test]
fn address_space_is_round() {
// addresses written past the last address 'loop' back to 0+(offset - MAX_SIZE)
let max_offset = SIZE_32KB;
let test_offset = max_offset;
// all zero
let mut ram = Hm62256::default();
// write FF to the addresss after the last
ram.write(&(test_offset as u16), &0xff);
// check all the ram for anything that isn't 0x00
assert_eq!(ram.read(&(0x0000)), 0xff);
for offset in 1..SIZE_32KB {
println!("Testing offset {offset:04x} for 0x00");
assert_eq!(ram.read(&(offset as u16)), 0x00);
}
}
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
// Chip Select
pub(crate) cs: bool,
// Write Enable
pub(crate) we: bool,
// Output Enable
pub(crate) oe: bool
}
+17
View File
@@ -0,0 +1,17 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
impl Hm62256 {
pub fn new(base_offset: u16) -> Self {
Self {
offset: base_offset,
max_offset: base_offset + SIZE_32KB as u16,
data: vec![0; SIZE_32KB].into_boxed_slice(),
address_bus: 0x0000,
data_bus: 0x00,
cs: false,
oe: false,
we: false
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
use crate::periph::ram_chip::RamChip;
use crate::traits::bus_device::BusDevice;
use crate::traits::ram_chip::RamChip;
impl RamChip for Hm62256 {
fn write(&mut self, offset: &u16, value: &u8) {
+4 -10
View File
@@ -1,18 +1,12 @@
use log::debug;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
use crate::periph::rom_chip::RomChip;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
impl RomChip for Hm62256 {
fn read(&self, offset: &u16) -> u8 {
// loops memory around past 32k
let effective = *offset as i32 % SIZE_32KB as i32;
self.data[effective as usize]
}
fn program(_: &[u8; SIZE_32KB]) -> Box<Self> {
fn program(_: &[u8]) -> Box<Self> {
debug!("Dont program ram.");
Hm62256::default().into()
}
+32 -26
View File
@@ -1,35 +1,41 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
impl Hm62256 {
fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
let new_data_bus = if read_mode {
// reading from ram
self.data[address_bus as usize]
fn max_address(&self) -> u16 {
self.offset + SIZE_32KB as u16
}
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
if !(address_bus >= self.offset && address_bus < self.max_address()) {
return (address_bus, data_bus);
}
self.address_bus = address_bus;
self.data_bus = data_bus;
let addr = address_bus.wrapping_sub(self.offset) + self.offset;
// did we want to talk to the chip...
if !cs {
return (address_bus, data_bus);
}
// ...or are we outside the range?
if (addr - self.offset) > SIZE_32KB as u16 {
return (address_bus, data_bus);
}
// ok. lets see what we are dealing with
self.data_bus = if read_mode {
let new_value = self.data[addr as usize];
new_value
} else {
// writing to ram
self.data[address_bus as usize] = data_bus.into();
self.data[addr as usize] = data_bus.into();
data_bus
};
(address_bus, new_data_bus)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn write_to_memory_read_back_works_at_0() {
let mut ram = Hm62256::default();
// load the data to ram
ram.tick(0x0000, 0xab, false);
// read the data back
let (_, new_data) = ram.tick(0x0000, 0x00, true);
assert_eq!(new_data, 0xab);
(self.address_bus, self.data_bus)
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+---+
| 6 | 7 | 8 | 9 | A | B |
+---+---+---+---+---+---+
| C | D | E | F | AD| DA|
+---+---+---+---+---+---+
| + | PC| ST| RS| | |
+---+---+---+---+---+---+
*/
pub struct Kim1Keypad {
pub keys: [bool; 23],
pub stepping: bool
}
impl Kim1Keypad {
pub fn dump(&self) {
println!("Dumping state of keypad");
}
}
impl Kim1Keypad {
fn keyid(from: u8) -> usize{
(from % 23) as usize
}
pub fn new() -> Self {
Kim1Keypad {
keys: [false; 23],
stepping: false
}
}
pub fn toggle_stepping(&mut self) {
self.stepping = !self.stepping;;
}
pub fn set_stepping(&mut self, new_state: bool) {
self.stepping = new_state
}
pub fn press_key(&mut self, key_to_press: u8) {
self.keys[Self::keyid(key_to_press)] = true;
}
pub fn release_key(&mut self, key_to_release: u8) {
self.keys[Self::keyid(key_to_release)] = false;
}
pub fn is_pressed(&self, key: u8) -> bool {
self.keys[Self::keyid(key)]
}
}
+12 -5
View File
@@ -1,6 +1,13 @@
pub mod rom_chip;
pub mod kim1_keypad;
pub mod at28c256;
pub mod hm62256;
pub mod ram_chip;
pub mod mos6522;
pub mod at28c256; // EEPROM with 32KB/256Kbit
pub mod hm62256; // RAM with 32KBit/256Kbit
pub mod mos6520; // PIA
pub mod mos6522; // PIA
pub mod mos6530; // RRIOT ROM, RAM, IO, Timer
pub mod mos6532; // PIA RAM, IO, Timer
pub mod mos6526;
mod mos6540;
mod mos6111;
// CIA Parallel, Serial, Interval Timers, Time Of Day
+50
View File
@@ -0,0 +1,50 @@
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
// MOS6111
// AKA MCS6111
// 128B/1024b RAM
pub struct Mos6111 {
data: Box<[u8]>,
offset: u16,
max_offset: u16
}
impl Mos6111 {
pub fn new(min_offset: u16, max_offset: u16) -> Self {
Mos6111 {
data: Box::new([0x00u8; 64]),
offset: min_offset,
max_offset
}
}
}
impl BusDevice for Mos6111 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn data_bus(&self) -> u8 {
todo!()
}
fn set_address_bus(&mut self, new_value: u16) {
todo!()
}
fn set_data_bus(&mut self, new_value: u8) {
todo!()
}
}
impl MemoryChip for Mos6111 {
fn read(&self, offset: &u16) -> u8 {
println!("IA = {}", self.internal_address(*offset));
0x00
}
}
+26
View File
@@ -0,0 +1,26 @@
use crate::periph::mos6520::Mos6520;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6520 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 { self.max_offset }
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+10
View File
@@ -0,0 +1,10 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip for Mos6520 {
fn read(&self, offset: &u16) -> u8 {
debug!("This has no ROM ${offset:04x}");
0
}
}
+54
View File
@@ -0,0 +1,54 @@
pub mod reset;
pub mod bus_device;
pub mod new;
pub mod tick;
pub mod rom_chip;
pub mod ram_chip;
pub mod memory_chip;
pub mod pia_chip;
use crate::traits::bus_device::BusDevice;
use crate::traits::gpio_chip::GpioChip;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
/*
The MCS6520 Peripheral Adapter is designed to solve a broad range of peripheral
control problems in the implementation of microcomputer systems. This device allows
a very effective trade-off between software and hardware by providing significant
capability and flexibility in a low cost chip. When coupled with the power and
speed of the MCS6500 family of microprocessors, the MCS6S20 allows implementation
of very complex systems at a minimum overall cost.
Control of peripheral devices is handled primarily through two 8-bit bi-directional ports.
Each of these lines can be programmed to act as either an input or
an output. In addition, four peripheral control/interrupt input lines are provided.
These lines can be used to interrupt the processor or for "hand-shaking" data
be tween the processor and a peripheral device.
*/
pub struct Mos6520 {
// Parallel ports A & B data registers
pub port_a: u8,
pub out_a: u8,
pub in_a: u8,
pub ddra: u8,
pub port_b: u8,
pub out_b: u8,
pub in_b: u8,
pub ddrb: u8,
// Interrupt control register
pub icr: u8,
// External Address and Data Bus
pub address_bus: u16,
pub data_bus: u8,
// Offsets
pub offset: u16,
pub max_offset: u16
}
impl Mos6520 {
pub fn debug_dump(&self) {
println!("DUMPING STATE: \nPORT_A:\t{:08b}\nIN_A:\t{:08b}\nOUT_A:\t{:08b}\nDDRA:\t{:08b}", self.port_a, self.in_a, self.out_a, self.ddra);
}
}
+21
View File
@@ -0,0 +1,21 @@
use crate::periph::mos6520::Mos6520;
impl Mos6520 {
pub fn new(start_offset: u16) -> Self {
Self {
port_a: 0,
out_a: 0,
port_b: 0,
out_b: 0,
ddra: 0,
ddrb: 0,
icr: 0,
address_bus: 0,
data_bus: 0,
offset: start_offset,
max_offset: start_offset + 4,
in_a: 0,
in_b: 0,
}
}
}
+101
View File
@@ -0,0 +1,101 @@
use crate::periph::mos6520::Mos6520;
use crate::traits::gpio_chip::{GpioChip, GpioChipPorts};
use crate::traits::pia_chip::PiaChip;
impl GpioChip for Mos6520 {
fn set_port(&mut self, new_value: u8, port: GpioChipPorts) {
match port {
GpioChipPorts::PORT_A => {
self.port_a = new_value
}
GpioChipPorts::PORT_B => {
self.port_b = new_value
}
}
}
fn set_ddr(&mut self, new_ddr_value: u8, port: GpioChipPorts) {
match port {
GpioChipPorts::PORT_A => {
self.ddra = new_ddr_value
}
GpioChipPorts::PORT_B => {
self.ddrb = new_ddr_value
}
}
}
fn get_port(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.port_a
}
GpioChipPorts::PORT_B => {
self.port_b
}
}
}
fn get_ddr(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.ddra
}
GpioChipPorts::PORT_B => {
self.ddrb
}
}
}
fn get_in(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.in_a
}
GpioChipPorts::PORT_B => {
self.in_b
}
}
}
fn get_out(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.port_a
}
GpioChipPorts::PORT_B => {
self.port_b
}
}
}
fn update_ports(&mut self) {
let (in_a, out_a) = Mos6520::split_port(self.port_a, self.ddra);
self.in_a = in_a;
self.out_a = out_a;
// Port B
let (in_b, out_b) = Mos6520::split_port(self.port_b, self.ddrb);
self.in_b = in_b;
self.out_b = out_b;
}
}
impl PiaChip for Mos6520 { }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_gpio_ports() {
let mut x = Mos6520::new(0x1000);
// offsets from 0x1000 -> 0x1004
}
}
+9
View File
@@ -0,0 +1,9 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::ram_chip::RamChip;
impl RamChip for Mos6520 {
fn write(&mut self, offset: &u16, value: &u8) {
debug!("This has no ROM / ${offset:04x} ${value:02x}");
}
}
+16
View File
@@ -0,0 +1,16 @@
use crate::periph::mos6520::Mos6520;
impl Mos6520 {
/// reset
///
/// Simulates holding Reset pin low
pub fn reset(&mut self) {
self.port_a = 0x00;
self.port_b = 0x00;
self.ddra = 0x00;
self.ddrb = 0x00;
self.icr = 0x00;
self.address_bus = 0x0000;
self.data_bus = 0x00;
}
}
+10
View File
@@ -0,0 +1,10 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::rom_chip::RomChip;
impl RomChip for Mos6520 {
fn program(new_data: &[u8]) -> Box<Self> {
debug!("This has no rom. Cant program.");
todo!()
}
}

Some files were not shown because too many files have changed in this diff Show More