add crtc character count

pull/31/head
AlinTigaeru 2023-02-10 22:25:50 +00:00
rodzic 552f9b4ff4
commit 179fce4e9f
6 zmienionych plików z 148 dodań i 89 usunięć

Wyświetl plik

@ -1,13 +1,14 @@
#include "cpc.h"
#include "pico.h"
#include "pico/stdlib.h"
#include "processor/Z80.h"
#include "roms/rom464.h"
extern "C" {
#include "emuapi.h"
#include "platform_config.h"
}
#include "processor/Z80.h"
#include "roms/rom464.h"
#include "crtc.h"
#include "ga.h"
@ -15,10 +16,10 @@ extern "C" {
* Declarations of instances of the RAM, VRAM, processor and other required components.
*/
static byte ram[0x10000]; // 64k
static byte RAM[0x10000]; // 64k
static byte bitstream[0x4000]; // 16k video ram to be used by PIO.
static Z80 cpu;
extern struct GA_Config ga_config;
static Z80 CPU;
extern struct GAConfig gateArray;
/*
* Implementations of system-specific emuapi Init, Step etc. functions.
@ -48,10 +49,10 @@ void cpc_Input(int bClick)
* System-specific implementations of the Z80 instructions required by the portable Z80 emulator.
*/
void OutZ80(register word Port, register byte Value)
void OutZ80(word Port, byte Value)
{
if(!(Port & 0x8000)) write_ga(Value); // The Gate Array is selected when bit 15 is set to 0.
if(!(Port & 0x4000)) write_crtc(Port, Value); // The CRTC is selected when bit 14 is set to 0.
if(!(Port & 0x8000)) writeGA(Value); // The Gate Array is selected when bit 15 is set to 0.
if(!(Port & 0x4000)) writeCRTC(Port, Value); // The CRTC is selected when bit 14 is set to 0.
if(!(Port & 0x2000))
{
// upper rom bank number. ROM banking needs to be done regardless of CPC model
@ -64,32 +65,31 @@ void OutZ80(register word Port, register byte Value)
}
}
byte InZ80(register word Port)
byte InZ80(word Port)
{
if(!(Port & 0x4000)) read_crtc(Port); // The CRTC is selected when bit 14 is set to 0.
return 0xFF;
if(!(Port & 0x4000)) return readCRTC(Port); // The CRTC is selected when bit 14 is set to 0.
}
#define LOWER_ROM_END 0x4000
#define UPPER_ROM_BEGIN 0xC000
void WrZ80(register word Addr, register byte Value)
void WrZ80(word Addr, byte Value)
{
ram[Addr] = Value;
RAM[Addr] = Value;
}
byte RdZ80(register word Addr)
byte RdZ80(word Addr)
{
if(Addr <= LOWER_ROM_END && ga_config.lower_rom_enable)
if(Addr <= LOWER_ROM_END && gateArray.lowerROMEnable)
{
return gb_rom_464_0[Addr];
}
else if(Addr >= UPPER_ROM_BEGIN && ga_config.upper_rom_enable)
else if(Addr >= UPPER_ROM_BEGIN && gateArray.upperROMEnable)
{
return gb_rom_464_1[Addr];
}
else
{
return ram[Addr];
return RAM[Addr];
}
}

Wyświetl plik

@ -1,4 +1,9 @@
#ifndef CPC_H_
#define CPC_H_
extern void cpc_Init(void);
extern void cpc_Step(void);
extern void cpc_Start(char* filename);
extern void cpc_Input(int bClick);
extern void cpc_Input(int bClick);
#endif

Wyświetl plik

@ -1,43 +1,79 @@
/**
* What 6845 primarily does is to generate CRT signals such as Horizontal Sync and Vertical Sync as well as
* video memory addresses to fetch pixel data.
* Gate Array works together in sync with CRTC, and is responsible for converting the pixel data in memory
* into video signals through an R2R DAC.
*/
#include "pico.h"
#include "pico/stdlib.h"
struct Registers {
uint8_t HorizontalTotal = 63;
uint8_t HorizontalDisplayed = 40;
uint8_t HorizontalSyncPosition = 46;
uint8_t HorizontalAndVerticalSyncWidths = 142;
uint8_t VerticalTotal = 38;
uint8_t VerticalTotalAdjust = 0;
uint8_t VerticalDisplayed = 25;
uint8_t VerticalSyncPosition = 30;
uint8_t InterlaceAndSkew = 0;
uint8_t MaximumRasterAddress = 7;
uint8_t CursorStartRaster = 0;
uint8_t CursorEndRaster = 0;
uint8_t DisplayStartAddressHigh = 48;
uint8_t DisplayStartAddressLow = 0;
uint8_t CursorAddressHigh = 0;
uint8_t CursorAddressLow = 0;
uint8_t LightPenAddressHigh = 0; // Read only
uint8_t LightPenAddressLow = 0; // Read only
} Registers;
#include "crtc.h"
void write_crtc(unsigned short address, unsigned short value)
uint8_t registers[16] = {
63, // horizontal_total
40, // horitzontal_displayed
46, // horizontal_sync_position
142, // horizontal_and_vertical_sync_widths
38, // vertical_total
0, // vertical_total_adjust
25, // vertical_displayed
30, // vertical_sync_position
0, // interlace_and_skew
7, // max_raster_address
0, // cursor_start_raster
0, // cursor_end_raster
48, // display_start_addr_high
0, // display_start_addr_low
0, // cursor_addr_high
0 // cursor_addr_low
};
uint8_t selectedRegister = 0;
uint8_t horizontal_counter = 0; // C0
uint8_t vertical_counter = 0; // C4
uint8_t scanline_counter = 0; // C9
uint8_t vertical_adjust_counter = 0;
uint16_t memory_address = 0;
void step()
{
return;
horizontal_counter++;
if(horizontal_counter == registers[0])
{
// horizontal counter is equal to the Horizontal Total Register.
horizontal_counter = 0;
scanline_counter++;
}
if(scanline_counter == registers[9])
{
// The counter for Maximum Raster Address is equal to it.
scanline_counter = 0;
vertical_counter++;
}
if(vertical_counter == registers[4])
{
// The vertical counter reaches the Vertical Total register.
if(vertical_adjust_counter == registers[5])
{
// TODO see how the vertical adjust counter is used by GA and rest of the system.
vertical_adjust_counter = 0;
vertical_counter = 0;
}
}
}
void read_crtc(unsigned short address)
// TODO hsync and vsync functions.
void writeCRTC(unsigned short address, uint8_t value)
{
switch(address & 0xFF00)
{
case 0xBF00: break;
case 0xBC00: selectedRegister = value & 0b11111;
case 0xBD00: registers[selectedRegister] = value;
}
return;
}
}
uint8_t readCRTC(unsigned short address)
{
switch(address & 0xFF00)
{
case 0xBF00: return registers[selectedRegister];
}
}

Wyświetl plik

@ -1,2 +1,12 @@
void write_crtc(unsigned short address, unsigned short value);
void read_crtc(unsigned short address);
#ifndef CRTC_H_
#define CRTC_H_
#ifndef PICO_H_
#include "pico.h"
#include "pico/stdlib.h"
#endif
void writeCRTC(unsigned short address, uint8_t value);
uint8_t readCRTC(unsigned short address);
#endif

Wyświetl plik

@ -1,23 +1,15 @@
/**
* Gate Array is connected to a 16Mhz clock signal, which is then divided to 4Mhz to feed the Z80, and 1Mhz for the CRTC.
* Gate Array's READY signal is connected to Z80's WAIT input for "memory contention".
* This means CPU execution is halted every time Gate Array and CPU accesses the memory at the same time.
* The reason for this is that both GA and the CPU share the same address/data bus for memory access.
*
* The Gate Array is responsible for the display (colour palette, resolution, horizontal and vertical sync), interrupt generation
* and memory arrangement.
*/
#include "pico.h"
#include "pico/stdlib.h"
#include "ga.h"
struct GA_Config ga_config;
struct GAConfig gaConfig;
/**
* Some of these colours are duplicates, because select_pen_colour() uses the least significant
* 5 bits to index into this array, so the duplicates prevent out-of-bounds read.
*/
struct RGB Palette[32] = {
struct RGB palette[32] = {
{50, 50, 50}, // White
{50, 50, 50}, // White
{0, 100, 50}, // Sea Green
@ -52,45 +44,51 @@ struct RGB Palette[32] = {
{50, 50, 100} // Pastel Blue
};
// TODO: Add a step() function, or something, that reads from the crtc's hsync and vsync and generates the actual
// pixel data based on its config data.
void step()
{
return;
}
void select_pen(register uint8_t value)
void select_pen(uint8_t value)
{
switch(value >> 4)
{
case 0b01:
// Select border.
ga_config.pen_selected = 0x10;
gaConfig.penSelected = 0x10;
break;
case 0b00:
// Bits 0-3 dictate the pen number
ga_config.pen_selected = value & 15;
gaConfig.penSelected = value & 15;
break;
}
}
void select_pen_colour(register uint8_t value)
void select_pen_colour(uint8_t value)
{
// Bits 0-4 of "value" specify the hardware colour number from the hardware colour palette.
// (i.e. which index into the Palette array of structs.)
ga_config.pen_colors[ga_config.pen_selected] = Palette[value & 31];
gaConfig.penColours[gaConfig.penSelected] = palette[value & 31];
}
void do_rom_bank_screen_cfg(register uint8_t value)
void do_rom_bank_screen_cfg(uint8_t value)
{
// Screen mode config, dictated by the least significant 2 bits.
switch(value & 3)
{
case 0b00:
// mode 0
// ga_config.ScreenMode = 0;
// ga_config.screen_mode = 0;
break;
case 0b01:
// mode 1
ga_config.screen_mode = 1;
gaConfig.screenMode = 1;
break;
case 0b10:
// mode 2
// ga_config.ScreenMode = 2;
// ga_config.screen_mode = 2;
break;
case 0b11:
// mode 3, unused.
@ -98,11 +96,11 @@ void do_rom_bank_screen_cfg(register uint8_t value)
}
// ROM enable flags.
if ((value >> 2) & 0b1) ga_config.lower_rom_enable = false; else ga_config.lower_rom_enable = true;
if ((value >> 3) & 0b1) ga_config.upper_rom_enable = false; else ga_config.upper_rom_enable = true;
if ((value >> 2) & 0b1) gaConfig.lowerROMEnable = false; else gaConfig.lowerROMEnable = true;
if ((value >> 3) & 0b1) gaConfig.upperROMEnable = false; else gaConfig.upperROMEnable = true;
// Interrupt generation control.
if ((value >> 4) & 0b1) ga_config.interrupt_delay = true; else ga_config.interrupt_delay = false;
if ((value >> 4) & 0b1) gaConfig.interruptDelay = true; else gaConfig.interruptDelay = false;
}
/** Bit 7 Bit 6 Function
@ -111,7 +109,7 @@ void do_rom_bank_screen_cfg(register uint8_t value)
* --1-- --0-- Select screen mode, ROM configuration and interrupt control
* --1-- --1-- RAM memory management
*/
void write_ga(register uint8_t value)
void write_ga(uint8_t value)
{
switch(value >> 6)
{

Wyświetl plik

@ -1,7 +1,15 @@
extern void write_ga(register uint8_t value);
void select_pen(register uint8_t value);
void select_pen_colour(register uint8_t value);
void rom_banking(register uint8_t value);
#ifndef GA_H_
#define GA_H_
#ifndef PICO_H_
#include "pico.h"
#include "pico/stdlib.h"
#endif
extern void writeGA(uint8_t value);
void selectPen(uint8_t value);
void selectPenColour(uint8_t value);
void romBanking(uint8_t value);
#define PEN_NUMBER 4 // Mode 0 has 16 pens, mode 1 has 4 pens and mode 2 has 2 pens.
@ -9,12 +17,14 @@ struct RGB {
uint8_t R, G, B;
};
struct GA_Config {
uint8_t pen_selected = 0;
RGB pen_colors[PEN_NUMBER];
uint8_t screen_mode = 1; // 0 -> 160x200 16c; 1 -> 320x200 4c; 2 -> 640x200 2c; 3 (undocumented) -> 160x200 4c.
bool upper_rom_enable = false;
bool lower_rom_enable = false;
bool interrupt_delay = false;
uint8_t ram_banking = 0; // unused in CPC 464
struct GAConfig {
uint8_t penSelected = 0;
RGB penColours[PEN_NUMBER];
uint8_t screenMode = 1; // 0 -> 160x200 16c; 1 -> 320x200 4c; 2 -> 640x200 2c; 3 (undocumented) -> 160x200 4c.
bool upperROMEnable = false;
bool lowerROMEnable = false;
bool interruptDelay = false;
uint8_t ramBanking = 0; // unused in CPC 464
};
#endif