/**
* This is an example for EhBasic
* based on the 6502 CPU emulator
* by Mike Chambers ([email protected])
* https://jeelabs.org/book/1549b/
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>
// Function declarations
uint16_t getpc();
uint8_t getop();
void exec6502(int32_t tickcount);
void reset6502();
void serout(uint8_t val);
uint8_t getkey();
void clearkey();
void print_state();
void load_program(const uint8_t *program, uint16_t size, uint16_t address);
// Global variables
volatile uint8_t curkey = 0;
// Serial output function optimized using registers directly
void serout(uint8_t val)
{
while (!(UCSR0A & (1 << UDRE0)))
; // Wait until buffer is ready
UDR0 = val; // Send data
}
// Get key input
uint8_t getkey()
{
return curkey;
}
// Clear key input
void clearkey()
{
curkey = 0;
}
// Optimized hexadecimal print function
void printhex(uint16_t val)
{
char buffer[5];
for (int i = 3; i >= 0; i--)
{
uint8_t digit = (val >> (i * 4)) & 0xF;
buffer[3 - i] = digit < 10 ? '0' + digit : 'A' + (digit - 10);
}
buffer[4] = '\0'; // Terminate string
for (int i = 0; i < 4; i++)
{
serout(buffer[i]); // Send each character via serial
}
serout('\n'); // Newline
}
// Function to print CPU state for debugging (optional)
void print_state()
{
uint16_t pc = getpc();
uint8_t opcode = getop();
// Implement function to print registers and status flags if needed
}
// Function to load a program into memory
void load_program(const uint8_t *program, uint16_t size, uint16_t address)
{
extern uint8_t RAM[]; // Access RAM from cpu.c
for (uint16_t i = 0; i < size; i++)
{
RAM[address + i] = program[i];
}
}
// Main loop
int main(void)
{
// Set up serial communication at 9600 bps using registers directly
UBRR0H = 0;
UBRR0L = 103; // Baud rate 9600 with 16 MHz clock
UCSR0A = 0;
UCSR0B = (1 << TXEN0) | (1 << RXEN0); // Enable TX and RX
UCSR0C =
(1 << UCSZ01) |
(1 << UCSZ00); // Configure 8N1 (8 data bits, no parity, 1 stop bit)
// Initialize the 6502 system
reset6502();
// Optionally load a program into memory
// const uint8_t program[] = { ... };
// load_program(program, sizeof(program), 0x8000);
while (1)
{
exec6502(1000); // Execute 1000 clock cycles
// Check if data is received via serial
if (UCSR0A & (1 << RXC0))
{
curkey = UDR0 & 0x7F; // Read received data and mask the parity bit
}
// Optional: Print CPU state for debugging
print_state();
// Small delay to prevent CPU hogging
_delay_ms(1);
}
return 0;
}