kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
add crtc character count
rodzic
552f9b4ff4
commit
179fce4e9f
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
#endif
|
|
@ -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++;
|
||||
}
|
||||
|
||||
void read_crtc(unsigned short address)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readCRTC(unsigned short address)
|
||||
{
|
||||
switch(address & 0xFF00)
|
||||
{
|
||||
case 0xBF00: return registers[selectedRegister];
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue