gigatron-rom
gigatron-rom copied to clipboard
v8080
In a similar manner as vCPU and v6502, add an interpreter for the 8080 instruction set as suggested by AlanC.
Justification: together with a block device (SDC/MMC), this opens the road to run CP/M on the Gigatron. 8080 is much simpler than Z80, and sufficient to get CP/M and applications running. We probably need to interface with CP/M over a SPI interface, instead of having the Gigatron act as a video terminal like we're used to now. (But we can still use the VGA output as a "god view" of the memory in the CP/M system. Thanks to OscarV for this idea.)
Points of attention:
- Take care that the address space is CP/M compatible. For example, the zero-page now isn't. Perhaps solve this by mapping it to a different physical page in the emulation. Otherwise by entering a completely new video loop for this mode.
- The parity flag is hard. For proper emulation it needs a lookup from RAM or ROM. But not all applications use this flag. Perhaps we can get very far by ignoring it, or by only looking at bit 0. (This is speculation).
- It's probably needed (and ok) to use zero-page variables in the userVars section (that is ≥$30). There's no need to preserve v6502 state when entering v8080 mode. We only need vCPU for the hardware layer, for example to do SYS calls into EPROM.
Some links, courtesy KenB for sending these:
From Propeller Forum
http://forums.parallax.com/discussion/110804/zicog-a-zilog-z80-emulator-in-1-cog
8080 Instruction Set - in octal with colour added
https://nanode0000.wordpress.com/2017/08/22/a-minimum-interactive-language-toolkit/
8080 instruction encoding:
Conventions in instruction source:
D = Destination register (8 bit)
S = Source register (8 bit)
RP = Register pair (16 bit)
# = 8 or 16 bit immediate operand
a = 16 bit Memory address
p = 8 bit port address
ccc = Conditional
Conventions in instruction encoding:
db = Data byte (8 bit)
lb = Low byte of 16 bit value
hb = High byte of 16 bit value
pa = Port address (8 bit)
Dest and Source reg fields:
111=A (Accumulator)
000=B
001=C
010=D
011=E
100=H
101=L
110=M (Memory reference through address in H:L)
Register pair 'RP' fields:
00=BC (B:C as 16 bit register)
01=DE (D:E as 16 bit register)
10=HL (H:L as 16 bit register)
11=SP (Stack pointer, refers to PSW (FLAGS:A) for PUSH/POP)
Condition code 'CCC' fields: (FLAGS: S Z x A x P x C)
000=NZ ('Z'ero flag not set)
001=Z ('Z'ero flag set)
010=NC ('C'arry flag not set)
011=C ('C'arry flag set)
100=PO ('P'arity flag not set - ODD)
101=PE ('P'arity flag set - EVEN)
110=P ('S'ign flag not set - POSITIVE)
111=M ('S'ign flag set - MINUS)
Inst Encoding Flags Description
----------------------------------------------------------------------
MOV D,S 01DDDSSS - Move register to register
MVI D,# 00DDD110 db - Move immediate to register
LXI RP,# 00RP0001 lb hb - Load register pair immediate
LDA a 00111010 lb hb - Load A from memory
STA a 00110010 lb hb - Store A to memory
LHLD a 00101010 lb hb - Load H:L from memory
SHLD a 00100010 lb hb - Store H:L to memory
LDAX RP 00RP1010 *1 - Load indirect through BC or DE
STAX RP 00RP0010 *1 - Store indirect through BC or DE
XCHG 11101011 - Exchange DE and HL content
ADD S 10000SSS ZSPCA Add register to A
ADI # 11000110 db ZSCPA Add immediate to A
ADC S 10001SSS ZSCPA Add register to A with carry
ACI # 11001110 db ZSCPA Add immediate to A with carry
SUB S 10010SSS ZSCPA Subtract register from A
SUI # 11010110 db ZSCPA Subtract immediate from A
SBB S 10011SSS ZSCPA Subtract register from A with borrow
SBI # 11011110 db ZSCPA Subtract immediate from A with borrow
INR D 00DDD100 ZSPA Increment register
DCR D 00DDD101 ZSPA Decrement register
INX RP 00RP0011 - Increment register pair
DCX RP 00RP1011 - Decrement register pair
DAD RP 00RP1001 C Add register pair to HL (16 bit add)
DAA 00100111 ZSPCA Decimal Adjust accumulator
ANA S 10100SSS ZSCPA AND register with A
ANI # 11100110 db ZSPCA AND immediate with A
ORA S 10110SSS ZSPCA OR register with A
ORI # 11110110 ZSPCA OR immediate with A
XRA S 10101SSS ZSPCA ExclusiveOR register with A
XRI # 11101110 db ZSPCA ExclusiveOR immediate with A
CMP S 10111SSS ZSPCA Compare register with A
CPI # 11111110 ZSPCA Compare immediate with A
RLC 00000111 C Rotate A left
RRC 00001111 C Rotate A right
RAL 00010111 C Rotate A left through carry
RAR 00011111 C Rotate A right through carry
CMA 00101111 - Compliment A
CMC 00111111 C Compliment Carry flag
STC 00110111 C Set Carry flag
JMP a 11000011 lb hb - Unconditional jump
Jccc a 11CCC010 lb hb - Conditional jump
CALL a 11001101 lb hb - Unconditional subroutine call
Cccc a 11CCC100 lb hb - Conditional subroutine call
RET 11001001 - Unconditional return from subroutine
Rccc 11CCC000 - Conditional return from subroutine
RST n 11NNN111 - Restart (Call n*8)
PCHL 11101001 - Jump to address in H:L
PUSH RP 11RP0101 *2 - Push register pair on the stack
POP RP 11RP0001 *2 *2 Pop register pair from the stack
XTHL 11100011 - Swap H:L with top word on stack
SPHL 11111001 - Set SP to content of H:L
IN p 11011011 pa - Read input port into A
OUT p 11010011 pa - Write A to output port
EI 11111011 - Enable interrupts
DI 11110011 - Disable interrupts
HLT 01110110 - Halt processor
NOP 00000000 - No operation
*1 = Only RP=00(BC) and 01(DE) are allowed for LDAX/STAX
*2 = RP=11 refers to PSW for PUSH/POP (cannot push/pop SP).
When PSW is POP'd, ALL flags are affected.
CP/M will happily run with a video terminal as well. It has no idea whether the BIOS call it made went out of a serial port, wrote to a textmode display, drew bitmaps or trapped out of emulation into something. It does need some simple terminal emulation logic but that's not hard and lots of old CP/M systems had that. Just don't pick horrors like VT100. ADM3A emulation was popular as being an early terminal it was simple and only had clear screen, home, up, down, left, right, set cursor position.
https://vt100.net/lsi/adm3a-mm.pdf
As an aside parity checking is indeed fairly rare and the only time you need to evaluate parity is on PUSH PSW and conditional jump using that flag. You need to store the byte whose parity is supposedly in the flag somewhere but you don't actually need to calculate the parity unless someone asks or it becomes observable by other means (PUSH PSW)...
For an early hack you may well still have to deal with Z80 aware code using
SUB A JP PE
to check Z80 v 8080.
Thanks! The worry about including the video terminal is more about the ~30K effective RAM pressure it creates than about anything else. 1 pixel = 1 byte, no tiling, while each line of 160 pixels leaves a gap of 96 bytes in that memory page. We can perhaps reduce it to ~20K by further reducing the number of text rows, and by sharing the black lines between them. [I'm planning something like that to make MS BASIC and Apple 1 BASIC work on the stock 32K system BTW.]. For SDC/MMC enabled systems we can safely assume 64K/128K is available, but still...
The other issue is if a 40x20 character video terminal is in any sense "workable" for applications other than Zork. We just have 160 pixels after all. (Or 256 if we allow scrolling, giving 64 chars)
My Epson PX-4 has a 40x8 display. In software it has an 80x25/40x43 display of which you see a window that tracks the cursor and can be scrolled around. It's quite usable for most things. Trek would suck I suspect though 8)