Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- //prototype external functions
- uint8_t i8080_read(uint16_t addr);
- void i8080_write(uint16_t addr, uint8_t value);
- uint8_t i8080_inport(uint8_t port);
- void i8080_outport(uint8_t port, uint8_t value);
- //end external functions
- #define reg16_PSW (((uint16_t)reg8[A] << 8) | (uint16_t)reg8[FLAGS])
- #define reg16_BC (((uint16_t)reg8[B] << 8) | (uint16_t)reg8[C])
- #define reg16_DE (((uint16_t)reg8[D] << 8) | (uint16_t)reg8[E])
- #define reg16_HL (((uint16_t)reg8[H] << 8) | (uint16_t)reg8[L])
- uint8_t reg8[9], INTE = 0;
- uint16_t reg_SP, reg_PC;
- #define B 0
- #define C 1
- #define D 2
- #define E 3
- #define H 4
- #define L 5
- #define M 6
- #define A 7
- #define FLAGS 8
- #define set_S() reg8[FLAGS] |= 0x80
- #define set_Z() reg8[FLAGS] |= 0x40
- #define set_AC() reg8[FLAGS] |= 0x10
- #define set_P() reg8[FLAGS] |= 0x04
- #define set_C() reg8[FLAGS] |= 0x01
- #define clear_S() reg8[FLAGS] &= 0x7F
- #define clear_Z() reg8[FLAGS] &= 0xBF
- #define clear_AC() reg8[FLAGS] &= 0xEF
- #define clear_P() reg8[FLAGS] &= 0xFB
- #define clear_C() reg8[FLAGS] &= 0xFE
- #define test_S() (reg8[FLAGS] & 0x80)
- #define test_Z() (reg8[FLAGS] & 0x40)
- #define test_AC() (reg8[FLAGS] & 0x10)
- #define test_P() (reg8[FLAGS] & 0x04)
- #define test_C() (reg8[FLAGS] & 0x01)
- static const uint8_t parity[0x100] = {
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
- };
- uint16_t read_RP(uint8_t rp) {
- switch (rp) {
- case 0x00:
- return reg16_BC;
- case 0x01:
- return reg16_DE;
- case 0x02:
- return reg16_HL;
- case 0x03:
- return reg_SP;
- }
- return 0;
- }
- uint16_t read_RP_PUSHPOP(uint8_t rp) {
- switch (rp) {
- case 0x00:
- return reg16_BC;
- case 0x01:
- return reg16_DE;
- case 0x02:
- return reg16_HL;
- case 0x03:
- return reg16_PSW;
- }
- return 0;
- }
- void write_RP(uint8_t rp, uint8_t lb, uint8_t hb) {
- switch (rp) {
- case 0x00:
- reg8[C] = lb;
- reg8[B] = hb;
- break;
- case 0x01:
- reg8[E] = lb;
- reg8[D] = hb;
- break;
- case 0x02:
- reg8[L] = lb;
- reg8[H] = hb;
- break;
- case 0x03:
- reg_SP = (uint16_t)lb | ((uint16_t)hb << 8);
- break;
- }
- }
- void write16_RP(uint8_t rp, uint16_t value) {
- switch (rp) {
- case 0x00:
- reg8[C] = value & 0x00FF;
- reg8[B] = value >> 8;
- break;
- case 0x01:
- reg8[E] = value & 0x00FF;
- reg8[D] = value >> 8;
- break;
- case 0x02:
- reg8[L] = value & 0x00FF;
- reg8[H] = value >> 8;
- break;
- case 0x03:
- reg_SP = value;
- break;
- }
- }
- void write16_RP_PUSHPOP(uint8_t rp, uint16_t value) {
- switch (rp) {
- case 0x00:
- reg8[C] = value & 0x00FF;
- reg8[B] = value >> 8;
- break;
- case 0x01:
- reg8[E] = value & 0x00FF;
- reg8[D] = value >> 8;
- break;
- case 0x02:
- reg8[L] = value & 0x00FF;
- reg8[H] = value >> 8;
- break;
- case 0x03:
- reg8[FLAGS] = value & 0x00FF;
- reg8[A] = value >> 8;
- break;
- }
- }
- void calc_SZP(uint8_t value) {
- if (value == 0) set_Z(); else clear_Z();
- if (value & 0x80) set_S(); else clear_S();
- if (parity[value]) set_P(); else clear_P();
- }
- void calc_AC(uint8_t val1, uint8_t val2) {
- if (((val1 & 7) + (val2 & 7)) & 0xF0) set_AC(); else clear_AC();
- }
- void calc_subAC(int8_t val1, uint8_t val2) {
- if (((val1 & 7) - (val2 & 7)) & 0xF0) set_AC(); else clear_AC();
- }
- uint8_t test_cond(uint8_t code) {
- switch (code) {
- case 0: //Z not set
- if (!test_Z()) return 1; else return 0;
- case 1: //Z set
- if (test_Z()) return 1; else return 0;
- case 2: //C not set
- if (!test_C()) return 1; else return 0;
- case 3: //C set
- if (test_C()) return 1; else return 0;
- case 4: //P not set
- if (!test_P()) return 1; else return 0;
- case 5: //P set
- if (test_P()) return 1; else return 0;
- case 6: //S not set
- if (!test_S()) return 1; else return 0;
- case 7: //S set
- if (test_S()) return 1; else return 0;
- }
- return 0;
- }
- void i8080_push(uint16_t value) {
- i8080_write(--reg_SP, value >> 8);
- i8080_write(--reg_SP, (uint8_t)value);
- }
- uint16_t i8080_pop() {
- uint16_t temp;
- temp = i8080_read(reg_SP++);
- temp |= (uint16_t)i8080_read(reg_SP++) << 8;
- return temp;
- }
- void i8080_interrupt(uint8_t n) {
- if (!INTE) return;
- i8080_push(reg_PC);
- reg_PC = (uint16_t)n << 3;
- INTE = 0;
- }
- void i8080_jump(uint16_t addr) {
- reg_PC = addr;
- }
- void i8080_reset() {
- reg_PC = reg_SP = 0x0000;
- reg8[FLAGS] = 0x02;
- }
- void write_reg8(uint8_t reg, uint8_t value) {
- if (reg == M) {
- i8080_write(reg16_HL, value);
- } else {
- reg8[reg] = value;
- }
- }
- uint8_t read_reg8(uint8_t reg) {
- if (reg == M) {
- return i8080_read(reg16_HL);
- } else {
- return reg8[reg];
- }
- }
- void i8080_exec(int cycles) {
- uint8_t opcode, temp8, reg;
- uint16_t temp16;
- uint32_t temp32;
- while (cycles--) {
- opcode = i8080_read(reg_PC++);
- if ((opcode & 0xC0) == 0x40) { //MOV D,S - move register to register
- write_reg8((opcode >> 3) & 7, read_reg8(opcode & 7));
- }
- else if ((opcode & 0xC7) == 0x06) { //MVI D,# - move immediate to register
- write_reg8((opcode >> 3) & 7, i8080_read(reg_PC++));
- }
- else if ((opcode & 0xCF) == 0x01) { //LXI RP,# - load register pair immediate
- temp8 = (opcode >> 4) & 3;
- write_RP(temp8, i8080_read(reg_PC), i8080_read(reg_PC + 1));
- reg_PC += 2;
- }
- else if (opcode == 0x3A) { //LDA a - load A from memory
- temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8);
- reg8[A] = i8080_read(temp16);
- reg_PC += 2;
- }
- else if (opcode == 0x32) { //STA a - store A to memory
- temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8);
- i8080_write(temp16, reg8[A]);
- reg_PC += 2;
- }
- else if (opcode == 0x2A) { //LHLD a - load H:L from memory
- temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8);
- reg8[L] = i8080_read(temp16++);
- reg8[H] = i8080_read(temp16);
- reg_PC += 2;
- }
- else if (opcode == 0x22) { //SHLD a - store H:L to memory
- temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8);
- i8080_write(temp16++, reg8[L]);
- i8080_write(temp16, reg8[H]);
- reg_PC += 2;
- }
- else if ((opcode & 0xEF) == 0x0A) { //LDAX RP - load A indirect through BC or DE
- reg8[A] = i8080_read(((opcode >> 4) & 1) ? reg16_DE : reg16_BC);
- }
- else if ((opcode & 0xEF) == 0x02) { //STAX RP - store A indirect through BC or DE
- i8080_write(((opcode >> 4) & 1) ? reg16_DE : reg16_BC, reg8[A]);
- }
- else if (opcode == 0xEB) { //XCHG - exchange DE and HL content
- temp8 = reg8[D];
- reg8[D] = reg8[H];
- reg8[H] = temp8;
- temp8 = reg8[E];
- reg8[E] = reg8[L];
- reg8[L] = temp8;
- }
- else if ((opcode & 0xF8) == 0x80) { //ADD S - add register or memory to A
- temp8 = read_reg8(opcode & 7); //reg8[opcode & 7];
- temp16 = (uint16_t)reg8[A] + (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_AC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if (opcode == 0xC6) { //ADI # - add immediate to A
- temp8 = i8080_read(reg_PC++);
- temp16 = (uint16_t)reg8[A] + (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_AC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if ((opcode & 0xF8) == 0x88) { //ADC S - add register or memory to A with carry
- temp8 = read_reg8(opcode & 7); //reg8[opcode & 7] + (test_C() ? 1 : 0);
- temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)(test_C() ? 1 : 0);
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_AC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if (opcode == 0xCE) { //ACI # - add immediate to A with carry
- temp8 = i8080_read(reg_PC++);
- temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)(test_C() ? 1 : 0);
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_AC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if ((opcode & 0xF8) == 0x90) { //SUB S - subtract register or memory from A
- temp8 = read_reg8(opcode & 7); //reg8[opcode & 7];
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if (opcode == 0xD6) { //SUI # - subtract immediate from A
- temp8 = i8080_read(reg_PC++);
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if ((opcode & 0xF8) == 0x98) { //SBB S - subtract register or memory from A with borrow
- temp8 = read_reg8(opcode & 7); //reg8[opcode & 7] + (test_C() ? 1 : 0);
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)(test_C() ? 1 : 0);
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if (opcode == 0xDE) { //SBI # - subtract immediate from A with borrow
- temp8 = i8080_read(reg_PC++);
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)(test_C() ? 1 : 0);
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if ((opcode & 0xC7) == 0x04) { //INR D - increment register
- reg = (opcode >> 3) & 7;
- temp8 = read_reg8(reg); //reg8[reg];
- calc_AC(temp8, 1);
- calc_SZP(temp8 + 1);
- write_reg8(reg, temp8 + 1); //reg8[reg]++;
- }
- else if ((opcode & 0xC7) == 0x05) { //DCR D - decrement register
- reg = (opcode >> 3) & 7;
- temp8 = read_reg8(reg); //reg8[reg];
- calc_subAC(temp8, 1);
- calc_SZP(temp8 - 1);
- write_reg8(reg, temp8 - 1); //reg8[reg]--;
- }
- else if ((opcode & 0xCF) == 0x03) { //INX RP - increment register pair
- reg = (opcode >> 4) & 3;
- write16_RP(reg, read_RP(reg) + 1);
- }
- else if ((opcode & 0xCF) == 0x0B) { //DCX RP - decrement register pair
- reg = (opcode >> 4) & 3;
- write16_RP(reg, read_RP(reg) - 1);
- }
- else if ((opcode & 0xCF) == 0x09) { //DAD RP - add register pair to HL
- reg = (opcode >> 4) & 3;
- temp32 = (uint32_t)reg16_HL + (uint32_t)read_RP(reg);
- write16_RP(2, (uint16_t)temp32);
- if (temp32 & 0xFFFF0000) set_C(); else clear_C();
- }
- else if (opcode == 0x27) { //DAA - decimal adjust accumulator
- temp16 = reg8[A];
- if (((temp16 & 0x0F) > 0x09) || test_AC()) {
- if (((temp16 & 0x0F) + 0x06) & 0xF0) set_AC(); else clear_AC();
- temp16 += 0x06;
- }
- if (((temp16 & 0xF0) > 0x90) || test_C()) {
- if ((temp16 + 0x60) & 0xFF00) set_C(); else clear_C();
- temp16 += 0x60;
- }
- calc_SZP((uint8_t)temp16);
- reg8[A] = (uint8_t)temp16;
- }
- else if ((opcode & 0xF8) == 0xA0) { //ANA S - AND register with A
- reg8[A] &= read_reg8(opcode & 7); //reg8[opcode & 7];
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if (opcode == 0xE6) { //ANI # - AND immediate with A
- reg8[A] &= i8080_read(reg_PC++);
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if ((opcode & 0xF8) == 0xB0) { //ORA S - OR register with A
- reg8[A] |= read_reg8(opcode & 7); //reg8[opcode & 7];
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if (opcode == 0xF6) { //ORI # - OR immediate with A
- reg8[A] |= i8080_read(reg_PC++);
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if ((opcode & 0xF8) == 0xA8) { //XRA S - XOR register with A
- reg8[A] ^= read_reg8(opcode & 7); //reg8[opcode & 7];
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if (opcode == 0xEE) { //XRI # - XOR immediate with A
- reg8[A] ^= i8080_read(reg_PC++);
- clear_C();
- calc_SZP(reg8[A]);
- }
- else if ((opcode & 0xF8) == 0xB8) { //CMP S - compare register with A
- temp8 = read_reg8(opcode & 7); //reg8[opcode & 7];
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- }
- else if (opcode == 0xFE) { //CPI # - compare immediate with A
- temp8 = i8080_read(reg_PC++);
- temp16 = (uint16_t)reg8[A] - (uint16_t)temp8;
- if (temp16 & 0xFF00) set_C(); else clear_C();
- calc_subAC(reg8[A], temp8);
- calc_SZP((uint8_t)temp16);
- }
- else if (opcode == 0x07) { //RLC - rotate A left
- if (reg8[A] & 0x80) set_C(); else clear_C();
- reg8[A] = (reg8[A] >> 7) | (reg8[A] << 1);
- }
- else if (opcode == 0x0F) { //RRC - rotate A right
- if (reg8[A] & 0x01) set_C(); else clear_C();
- reg8[A] = (reg8[A] << 7) | (reg8[A] >> 1);
- }
- else if (opcode == 0x17) { //RAL - rotate A left through carry
- temp8 = test_C();
- if (reg8[A] & 0x80) set_C(); else clear_C();
- reg8[A] = (reg8[A] << 1) | temp8; //TODO: did i do this right??
- }
- else if (opcode == 0x1F) { //RAR - rotate A right through carry
- temp8 = test_C();
- if (reg8[A] & 0x01) set_C(); else clear_C();
- reg8[A] = (reg8[A] >> 1) | (temp8 << 7); //TODO: did i do this right??
- }
- else if (opcode == 0x2F) { //CMA - compliment A
- reg8[A] = ~reg8[A];
- }
- else if (opcode == 0x3F) { //CMC - compliment carry flag
- reg8[FLAGS] ^= 1;
- }
- else if (opcode == 0x37) { //STC - set carry flag
- set_C();
- }
- else if (opcode == 0xC3) { //JMP a - unconditional jump
- temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8);
- reg_PC = temp16;
- }
- else if ((opcode & 0xC7) == 0xC2) { //Jccc a - conditional jump
- temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8);
- if (test_cond((opcode >> 3) & 7)) reg_PC = temp16; else reg_PC += 2;
- }
- else if (opcode == 0xCD) { //CALL a - unconditional call
- temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8);
- i8080_push(reg_PC + 2);
- reg_PC = temp16;
- }
- else if ((opcode & 0xC7) == 0xC4) { //Cccc a - conditional call
- temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8);
- if (test_cond((opcode >> 3) & 7)) {
- i8080_push(reg_PC + 2);
- reg_PC = temp16;
- } else {
- reg_PC += 2;
- }
- }
- else if (opcode == 0xC9) { //RET - unconditional return
- reg_PC = i8080_pop();
- }
- else if ((opcode & 0xC7) == 0xC0) { //Rccc - conditional return
- if (test_cond((opcode >> 3) & 7)) reg_PC = i8080_pop();
- }
- else if (opcode == 0xC7) { //RST n - restart (call n*8)
- i8080_push(reg_PC);
- reg_PC = (uint16_t)((opcode >> 3) & 7) << 3;
- }
- else if (opcode == 0xE9) { //PCHL - jump to address in H:L
- reg_PC = reg16_HL;
- }
- else if ((opcode & 0xCF) == 0xC5) { //PUSH RP - push register pair on the stack
- reg = (opcode >> 4) & 3;
- i8080_push(read_RP_PUSHPOP(reg));
- }
- else if ((opcode & 0xCF) == 0xC1) { //POP RP - pop register pair from the stack
- reg = (opcode >> 4) & 3;
- write16_RP_PUSHPOP(reg, i8080_pop());
- }
- else if (opcode == 0xE3) { //XTHL - swap H:L with top word on stack
- temp16 = i8080_pop();
- i8080_push(reg16_HL);
- write16_RP(2, temp16);
- }
- else if (opcode == 0xF9) { //SPHL - set SP to content of HL
- reg_SP = reg16_HL;
- }
- else if (opcode == 0xDB) { //IN p - read input port into A
- reg8[A] = i8080_inport(i8080_read(reg_PC++));
- }
- else if (opcode == 0xD3) { //OUT p - write A to output port
- i8080_outport(i8080_read(reg_PC++), reg8[A]);
- }
- else if (opcode == 0xFB) { //EI - enable interrupts
- INTE = 1;
- }
- else if (opcode == 0xF3) { //DI - disbale interrupts
- INTE = 0;
- }
- else if (opcode == 0x76) { //HLT - halt processor
- reg_PC--;
- }
- else if (opcode == 0x00) { //NOP - no operation
- }
- else {
- printf("UNRECOGNIZED INSTRUCTION @ %04Xh: %02X\n", reg_PC - 1, opcode);
- exit(0);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement