buggy video still, crashes after a while

pull/31/head
AlinTigaeru 2023-02-16 17:58:48 +00:00
rodzic 4a399d7763
commit bd3f4ec1b1
11 zmienionych plików z 225 dodań i 138 usunięć

Wyświetl plik

@ -11,16 +11,25 @@ extern "C" {
#include "platform_config.h"
}
#include "processor/Z80.h"
#include "roms/rom464.h"
#include "crtc.h"
#include "ga.h"
#include "roms/rom464.h"
#define WIDTH 320
#define HEIGHT 200
#define CYCLES_PER_FRAME 19968
#define NBLINES 312
#define CYCLES_PER_STEP CYCLES_PER_FRAME/NBLINES
/*
* Declarations of instances of the RAM, VRAM, processor and other required components.
*/
char osROM[0x4000];
char basicROM[0x4000];
uint8_t RAM[0x10000]; // 64k
uint8_t bitstream[0x4000]; // 16k video ram to be used by PIO.
unsigned char* bitstream = 0; // 16k video ram to be used by PIO.
static Z80 CPU;
bool interruptGenerated = false;
@ -28,53 +37,59 @@ bool interruptGenerated = false;
/*
* Implementations of system-specific emuapi Init, Step etc. functions.
*/
#define CYCLES_PER_FRAME 80000
#define NBLINES (1) //(48+192+56+16) //(32+256+32)
#define CYCLES_PER_STEP (CYCLES_PER_FRAME/NBLINES)
void cpc_Init(void)
{
for(int i = 0; i < PALETTE_SIZE; i++)
{
// R, G and B are not absolute RGB, they are percentegaes. TODO change that.
emu_SetPaletteEntry(palette[i].R, palette[i].G, palette[i].B, i);
}
if (bitstream == 0) bitstream = (unsigned char *)emu_Malloc(WIDTH*HEIGHT);
//memset(RAM, 0, sizeof(RAM));
ResetZ80(&CPU, CYCLES_PER_FRAME);
memset(RAM, 0, sizeof(RAM));
}
//ResetZ80(&CPU, CYCLES_PER_FRAME);
void cpc_Start(char* filename)
{
// Interrupts disabled, PC=0, enable low rom, disable high rom, gate array scanline counter = 0, write 0xC0 into GA.
// set memory to 0.
CPU.IFF = 0;
CPU.PC.W = 0x0000;
CPU.IRequest = INT_NONE;
gaConfig.lowerROMEnable = true;
gaConfig.upperROMEnable = false;
gaConfig.interruptCounter = 0;
writeGA(0xC0);
// writeGA(0x89);
// CPU.PC.W = 0x580;
}
void cpc_Step(void)
{
// printf("Enter step\n");
// TODO I don't think I am actually loading the ROM and having the CPU start executing w/e's there.
for(int i = 0; i<CYCLES_PER_FRAME; i++)
{
ExecZ80(&CPU, 1);
crtc_step();
interruptGenerated = ga_step();
if(interruptGenerated)
{
CPU.IRequest = INT_RST38;
gaConfig.interruptCounter &= 0x1F;
// RunZ80(&CPU);
//printf("Current program counter: %d \n", CPU.PC.W);
for(int i = 0; i < NBLINES; i++)
{
ExecZ80(&CPU, CYCLES_PER_STEP);
for(int j = 0; j < CYCLES_PER_STEP; j++)
{
crtc_step();
interruptGenerated = ga_step();
if(interruptGenerated)
{
printf("Interrupting! Jumping to \n");
IntZ80(&CPU, INT_IRQ);
gaConfig.interruptCounter &= 0x1F;
}
}
emu_DrawLine8(bitstream, WIDTH, HEIGHT, i);
//printf("index %d: %c \n", i, bitstream + i);
}
else
{
CPU.IRequest = INT_NONE;
}
// printf("Executed %d steps in hardware\n", 256);
}
}
void cpc_Start(char* filename)
{
}
void cpc_Input(int bClick)
@ -82,11 +97,6 @@ void cpc_Input(int bClick)
}
void displayScreen()
{
}
/*
* System-specific implementations of the Z80 instructions required by the portable Z80 emulator.
*/
@ -107,6 +117,19 @@ void OutZ80(word Port, byte Value)
}
}
// word LoopZ80(Z80 *R)
// {
// if(interruptGenerated)
// {
// return INT_IRQ;
// }
// else
// {
// return INT_NONE;
// }
// }
byte InZ80(word Port)
{
if(!(Port & 0x4000)) return readCRTC(Port); // The CRTC is selected when bit 14 is set to 0.
@ -119,6 +142,8 @@ byte InZ80(word Port)
void WrZ80(word Addr, byte Value)
{
RAM[Addr] = Value;
//printf("Write %x at %x \n", Value, Addr);
}
void PatchZ80(Z80 *R)
@ -130,17 +155,17 @@ byte RdZ80(word Addr)
{
if(Addr <= LOWER_ROM_END && gaConfig.lowerROMEnable)
{
// printf("Reading from the OS ROM.\n");
// printf("At program counter %x, Z80 read from address %x in OS ROM\n", CPU.PC.W, Addr);
return gb_rom_464_0[Addr];
}
else if(Addr >= UPPER_ROM_BEGIN && gaConfig.upperROMEnable)
{
// printf("Reading from BASIC's ROM.\n");
// printf("At program counter %x, Z80 read from address %x in BASIC ROM\n", CPU.PC.W, Addr);
return gb_rom_464_1[Addr - 0xC000];
}
else
{
// printf("Reading from RAM.\n");
// printf("At program counter %x, Z80 read from address %x in RAM\n", CPU.PC.W, Addr);
return RAM[Addr];
}
}

Wyświetl plik

@ -7,7 +7,7 @@
#endif
extern uint8_t RAM[0x10000];
extern uint8_t bitstream[0x4000];
extern unsigned char* bitstream;
extern struct GAConfig gaConfig;
extern void cpc_Init(void);

Wyświetl plik

@ -41,29 +41,30 @@ void crtc_step()
horizontalCount = 0;
scanlineCount++;
// printf("Resetting horizontal counter!\n");
if(scanlineCount > registers[9])
{
// The counter for Maximum Raster Address is equal to it.
// The height of a character is 8 rasters, so when we reach 8 rasters we increment the char line count.
scanlineCount = 0;
characterLineCount++;
//printf("characterLineCount: %d \n", characterLineCount);
if(characterLineCount > registers[4])
{
// The vertical counter reaches the Vertical Total register.
characterLineCount = 0;
}
}
if(characterLineCount == 0)
{
memoryAddr = ((uint16_t) registers[12] << 8) | registers[13];
}
}
if(scanlineCount > registers[9])
{
// The counter for Maximum Raster Address is equal to it.
// The height of a character is 8 rasters, so when we reach 8 rasters we increment the char line count.
scanlineCount = 0;
characterLineCount++;
//printf("characterLineCount: %d \n", characterLineCount);
// printf("Resetting scanline counter!\n");
}
// printf("Scanline count: %d \n", scanlineCount);
if(characterLineCount > registers[4])
{
// The vertical counter reaches the Vertical Total register.
characterLineCount = 0;
}
if(horizontalCount == 0 && characterLineCount == 0)
{
memoryAddr = ((uint16_t) registers[12] << 8) | registers[13];
// printf("memoryAddr update! New value: %x \n", memoryAddr);
}
}
uint16_t crtc_generateAddress()
@ -77,10 +78,16 @@ uint16_t crtc_generateAddress()
uint16_t elevenToThirteenBits = (scanlineCount & 0b0000000000000111) << 11;
uint16_t fourteenFifteenBits = (memoryAddr & 0b0011000000000000) << 2;
//printf("memoryAddr: %x \n calculatedAddr: %x \n", memoryAddr, fourteenFifteenBits | elevenToThirteenBits | firstTenBits);
// printf("Address generated by the crtc: %x \n", fourteenFifteenBits | elevenToThirteenBits | firstTenBits);
return fourteenFifteenBits | elevenToThirteenBits | firstTenBits;
}
bool isWithinDisplay()
{
return horizontalCount < registers[0] && scanlineCount < registers[6];
}
bool isHSyncActive()
{
// HSYNC is active if the horizontal counter is in the
@ -93,10 +100,8 @@ bool isVSyncActive()
{
int8_t characterHeight = (int8_t) registers[9] + 1;
int8_t characterLinesCounted = (int8_t) characterLineCount - registers[7];
// printf("characterHeight: %d \ncharacterLineCount: %d \nscanlineCount: %d \n", characterHeight, characterLineCount, scanlineCount);
// printf("isVSyncActive value calculated: %d \n", characterHeight * characterLinesCounted + scanlineCount);
return characterHeight * characterLineCount + (int8_t) scanlineCount >= 0 &&
characterHeight * characterLineCount + (int8_t) scanlineCount <= 128;
return characterHeight * characterLineCount + (int8_t) scanlineCount >= 0 &&
characterHeight * characterLineCount + (int8_t) scanlineCount <= 128;
}

Wyświetl plik

@ -15,6 +15,7 @@ extern uint8_t verticalAdjustCount;
bool isHSyncActive();
bool isVSyncActive();
bool isWithinDisplay();
uint16_t crtc_generateAddress();
void crtc_step();
void writeCRTC(unsigned short address, uint8_t value);

Wyświetl plik

@ -7,7 +7,7 @@
/* Title */
#define TITLE " Amstrad CPC Emulator"
#define ROMSDIR "cpc"
#define ROMSDIR "roms"
#define emu_Init(ROM) {cpc_Init(); cpc_Start(ROM);}
#define emu_Step(x) {cpc_Step();}

Wyświetl plik

@ -2,10 +2,12 @@
#include "pico/stdlib.h"
#include <stdio.h>
#include <stdlib.h>
#include "ga.h"
#include "crtc.h"
#include "cpc.h"
struct GAConfig gaConfig;
/**
@ -13,38 +15,38 @@ struct GAConfig gaConfig;
* 5 bits to index into this array, so the duplicates prevent out-of-bounds read.
*/
struct RGB palette[32] = {
{50, 50, 50}, // White
{50, 50, 50}, // White
{0, 100, 50}, // Sea Green
{100, 100, 50}, // Pastel Yellow
{0, 0, 50}, // Blue
{100, 0, 50}, // Purple
{0, 50, 50}, // Cyan
{100, 50, 50}, // Pink
{100, 0, 50}, // Purple
{100, 100, 50}, // Pastel Yellow
{100, 100, 0}, // Bright Yellow
{100, 100, 100}, // Bright White
{100, 0, 0}, // Bright Red
{100, 0, 100}, // Bright Magenta
{100, 50, 0}, // Orange
{100, 50, 100}, // Pastel Magenta
{0, 0, 50}, // Blue
{0, 100, 50}, // Sea Green
{0, 100, 0}, // Bright Green
{0, 100, 100}, // Bright Cyan
{128, 128, 128}, // White
{128, 128, 128}, // White
{0, 255, 128}, // Sea Green
{255, 255, 128}, // Pastel Yellow
{0, 0, 128}, // Blue
{255, 0, 128}, // Purple
{0, 128, 128}, // Cyan
{255, 128, 128}, // Pink
{255, 0, 128}, // Purple
{255, 255, 128}, // Pastel Yellow
{255, 255, 0}, // Bright Yellow
{255, 255, 255}, // Bright White
{255, 0, 0}, // Bright Red
{255, 0, 255}, // Bright Magenta
{255, 128, 0}, // Orange
{255, 128, 255}, // Pastel Magenta
{0, 0, 128}, // Blue
{0, 255, 128}, // Sea Green
{0, 255, 0}, // Bright Green
{0, 255, 255}, // Bright Cyan
{0, 0, 0}, // Black
{0, 0, 100}, // Bright Blue
{0, 50, 0}, // Green
{0, 50, 100}, // Sky Blue
{50, 0, 50}, // Magenta
{50, 100, 50}, // Pastel Green
{50, 100, 0}, // Lime
{50, 100, 100}, // Pastel Cyan
{50, 0, 0}, // Red
{50, 0, 100}, // Mauve
{50, 50, 0}, // Yellow
{50, 50, 100} // Pastel Blue
{0, 0, 255}, // Bright Blue
{0, 128, 0}, // Green
{0, 128, 255}, // Sky Blue
{128, 0, 128}, // Magenta
{128, 255, 128}, // Pastel Green
{128, 255, 0}, // Lime
{128, 255, 255}, // Pastel Cyan
{128, 0, 0}, // Red
{128, 0, 255}, // Mauve
{128, 128, 0}, // Yellow
{128, 128, 255} // Pastel Blue
};
bool updateInterrupts()
@ -85,48 +87,98 @@ bool updateInterrupts()
return interrupt_generated;
}
char convertPixelToVGA(uint8_t r, uint8_t g, uint8_t b)
{
return VGA_RGB(r,g,b);
}
void addressToPixels()
{
// When HSYNC is active Gate-Array outputs the palette colour black
if(gaConfig.hsyncActive)
{
*bitstream = convertPixelToVGA(gaConfig.penColours[19].R,
gaConfig.penColours[19].G,
gaConfig.penColours[19].B);
*bitstream++;
return;
}
for(int i = 0; i < 2; i++)
{
uint16_t address = crtc_generateAddress() + i;
//printf(" address from CRTC: %x \nRAM data: %x \n", address, RAM[address]);
uint8_t encodedByte = RAM[address];
if(RAM[address] != 0 && address >= 0xC000)
{
printf("CRTC generated addr: %x \nRAM[address]: %x \n", address, encodedByte);
uint8_t pixel0, pixel1, pixel2, pixel3;
uint8_t* pixels = (uint8_t*) calloc(4, 8*sizeof(uint8_t));
// if(address >= 0xC000)
// {
// printf("CRTC generated addr: %x \nRAM[address]: %x \n", address, encodedByte);
switch(gaConfig.screenMode)
{
case 0:
bitstream[address - 0xC000] = (encodedByte & 0x80) >> 7 |
(encodedByte & 0x08) >> 2 |
(encodedByte & 0x20) >> 3 |
(encodedByte & 0x02) << 2;
bitstream[address + 1 - 0xC000] = (encodedByte & 0x40) >> 6 |
(encodedByte & 0x04) >> 1 |
(encodedByte & 0x10) >> 2 |
(encodedByte & 0x01) << 3;
pixel0 = (encodedByte & 0x80) >> 7 |
(encodedByte & 0x08) >> 2 |
(encodedByte & 0x20) >> 3 |
(encodedByte & 0x02) << 2;
pixel1 = (encodedByte & 0x40) >> 6 |
(encodedByte & 0x04) >> 1 |
(encodedByte & 0x10) >> 2 |
(encodedByte & 0x01) << 3;
pixels[0] = pixel0;
pixels[1] = pixel1;
// TODO may not be correct, needs testing.
break;
case 1:
bitstream[address - 0xC000] = (encodedByte & 0x80) >> 7 |
(encodedByte & 0x08) >> 2;
bitstream[address + 1 - 0xC000] = (encodedByte & 0x40) >> 6 |
(encodedByte & 0x04) >> 1;
bitstream[address + 2 - 0xC000] = (encodedByte & 0x02) |
(encodedByte & 0x20) >> 5;
bitstream[address + 3 - 0xC000] = (encodedByte & 0x10) >> 4 |
(encodedByte & 0x01) << 1;
break;
case 2:
for (int j = 0; j < 8; j++)
// bitstream[address - 0xC000]
// bitstream[address + 1 - 0xC000]
// need to consider each color for the 2 pixels
for(int pixelIdx = 0; pixelIdx < 2; pixelIdx++)
{
bitstream[address + j - 0xC000] = (encodedByte >> 7 - j) & 1;
for(int color = 0; color < 4; color++)
{
bitstream[address + color - 0xC000] = convertPixelToVGA(gaConfig.penColours[pixels[pixelIdx]].R,
gaConfig.penColours[pixels[pixelIdx]].G,
gaConfig.penColours[pixels[pixelIdx]].B);
}
}
break;
}
case 1:
pixel0 = (encodedByte & 0x80) >> 7 |
(encodedByte & 0x08) >> 2;
pixel1 = (encodedByte & 0x40) >> 6 |
(encodedByte & 0x04) >> 1;
pixel2 = (encodedByte & 0x02) |
(encodedByte & 0x20) >> 5;
pixel3 = (encodedByte & 0x10) >> 4 |
(encodedByte & 0x01) << 1;
pixels[0] = pixel0;
pixels[1] = pixel1;
pixels[2] = pixel2;
pixels[3] = pixel3;
for(int pixelIdx = 0; pixelIdx < 4; pixelIdx++)
{
for(int color = 0; color < 2; color++)
{
bitstream[address + color - 0xC000] = convertPixelToVGA(gaConfig.penColours[pixels[pixelIdx]].R,
gaConfig.penColours[pixels[pixelIdx]].G,
gaConfig.penColours[pixels[pixelIdx]].B);
}
}
break;
case 2:
uint8_t pixel;
for (int color = 0; color < 8; color++)
{
pixel = (encodedByte >> 7 - color) & 1;
bitstream[address + color - 0xC000] = convertPixelToVGA(gaConfig.penColours[pixel].R,
gaConfig.penColours[pixel].G,
gaConfig.penColours[pixel].B);
}
break;
// }
}
free(pixels);
}
}
@ -134,7 +186,9 @@ bool ga_step()
{
// TODO add proper GA responses to hsync and vsync signals.
bool interruptGenerated = updateInterrupts();
addressToPixels();
// printf("Did the GA generate an interrupt? %d \n Interrupt counter: %d", interruptGenerated, gaConfig.interruptCounter);
if(memoryAddr != 0)
addressToPixels();
gaConfig.hsyncActive = isHSyncActive();
gaConfig.vsyncActive = isVSyncActive();
@ -166,9 +220,11 @@ void selectPenColour(uint8_t value)
void ROMMgmtAndScreenCfg(uint8_t value)
{
// Screen mode config, dictated by the least significant 2 bits.
if(!gaConfig.hsyncActive)
if(!gaConfig.hsyncActive && isHSyncActive())
{
// Screen mode config, dictated by the least significant 2 bits.
// Effective at next line.
switch(value & 3)
{
case 0b00:
@ -187,6 +243,7 @@ void ROMMgmtAndScreenCfg(uint8_t value)
// mode 3, unused.
break;
}
printf("Updated screen mode to mode %d", gaConfig.screenMode);
}
// ROM enable flags.

Wyświetl plik

@ -13,6 +13,7 @@ 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.
#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) )
struct RGB {
uint8_t R, G, B;

Wyświetl plik

@ -53,16 +53,15 @@ int main(void) {
tft.begin();
#endif
emu_init();
toggleMenu(false); // ####################################
while (true) {
if (menuActive()) {
uint16_t bClick = emu_DebounceLocalKeys();
int action = handleMenu(bClick);
int action = ACTION_RUNTFT; //handleMenu(bClick);
char * filename = menuSelection();
if (action == ACTION_RUNTFT) {
toggleMenu(false);
emu_Init(filename);
emu_start();
emu_Init(filename);
tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) );
tft.startDMA();
struct repeating_timer timer;
@ -71,11 +70,8 @@ int main(void) {
tft.waitSync();
}
else {
// tft.clear(VGA_RGB(200,0,0));
emu_Step();
emu_DrawScreen(bitstream, 320, 200, 1);
emu_Step();
tft.waitSync();
// tft.clear(VGA_RGB(250,0,0));
}
//int c = getchar_timeout_us(0);
//switch (c) {

Wyświetl plik

@ -699,7 +699,9 @@ word RunZ80(Z80 *R)
if(!DebugZ80(R)) return(R->PC.W);
#endif
I=OpZ80(R->PC.W++);
R->ICount-=Cycles[I];
switch(I)

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.