Skip to content

Commit for Foenix F256K retro-computer. #14029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

dtremblay
Copy link

@dtremblay dtremblay commented Aug 5, 2025

More information about the hardware is available here: https://wiki.f256foenix.com/

For the list of supported features, see: https://wiki.f256foenix.com/index.php?title=Emulation#MAME.

For ROMs, see the release page: https://github.com/dtremblay/mame/releases
The ROM is called f256k.zip - there is also a SD Card image available there.

Comment on lines 164 to 177
void f256_state::data_map(address_map &map)
{
map(0x0000, 0x1FFF).ram().share(IOPAGE0_TAG);
map(0x0000, 0x1FFF).ram().share(IOPAGE1_TAG);
map(0x0000, 0x1FFF).ram().share(IOPAGE2_TAG);
map(0x0000, 0x1FFF).ram().share(IOPAGE3_TAG);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? This will just map IOPAGE3_TAG for the address_space rule of last one wins, how it's supposed to really work?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is confusing. The F256K has an IO register in byte 0x01 which determines which IO devices to map. This way more devices can be supported with only a 16-bit bus.

Removed github workflow files.
Re-arranged the setters to follow the constructors in the main constructor.
Copy link
Author

@dtremblay dtremblay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the offending .github/workflow files.
Added the SPDX header to new files.
Fixed the setters to follow constructors.
Re-tested.

@dtremblay
Copy link
Author

Addressed all comments.

Copy link
Author

@dtremblay dtremblay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes committed.

@dtremblay dtremblay requested a review from ajrhacker August 6, 2025 21:38
@dtremblay dtremblay requested a review from angelosa August 7, 2025 07:29
@dtremblay
Copy link
Author

So... am I supposed to do something else to get this PR accepted? It seems to be stuck. The workflow hasn't been approved yet.

@stonedDiscord
Copy link
Contributor

stonedDiscord commented Aug 8, 2025

It sometimes takes a few days or weeks until a maintainer has time to look at PRs that aren't just a few lines or a new dump.
The workflow did run and it seems it failed.
Click the red X next to your latest commit above.

Comment on lines 244 to 257
uint8_t mmu = m_mmu_reg & 3;
uint16_t adj_addr = offset + 0x10;
uint8_t slot = adj_addr >> 13;
uint16_t low_addr = adj_addr & 0x1FFF;
uint8_t bank = mmu_lut[mmu * 8 + slot];

// fslot < 0x40 is RAM, greater is FLASH/ROM
if (bank < 0x40)
{
// Slot 6 is where I/O devices are located, when IO_DISABLE is 0
if (slot == 6 && (m_ioreg & 0x4) == 0)
{
switch (m_ioreg & 0x3)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel like this could be expressed with address_map_bank and use of memory_view specifically for the 0xc000-0xdfff area, to me it looks similar to a PC Engine or an OS-9 based machine like Hitachi S1.
Also: how much RAM this is really supposed to have?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The machine has 512K of flash, 512K of static RAM. There's also an extension cartridge for 256K available as flash or RAM.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't understand the memory bank documentation. Could this be done as an update? I intend to add other variants of the machine (with 65816 CPU, for example).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://wiki.f256foenix.com/index.php?title=Memory_Management

Need to point me where's the I/O explaination.

PS: yeah it can run OS-9, with a special 6809 flavour if I'm getting it right?

Copy link
Author

@dtremblay dtremblay Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The I/O page information is not available in the wiki, unfortunately. The PDF has the details: F256K PDF. See starting at page 14.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole address range from 0x0000 to 0xffff is mapped in 8K blocks using a control register at address 0x0.
The address from 0xc000 to 0xdfff can be mapped to memory or to I/O using control register at address 0x1.
I'm re-reading the MAME documentation to see how I can implement memory_bank and memory_view concepts.

@MooglyGuy
Copy link
Contributor

MooglyGuy commented Aug 8, 2025

One overarching bit of feedback, it's usually not ideal to suggest that feedback be done via a Discord server. Part of the point of a pull request is that the code review occurs within the pull request itself.

While there is certainly a particular generational shift towards the use of Discord as a substitute for websites, that isn't something that tends to be shared by the wider software development community, at least those old enough to have been doing professional software development for the past couple of decades.

@dtremblay
Copy link
Author

One overarching bit of feedback, it's usually not ideal to suggest that feedback be done via a Discord server. Part of the point of a pull request is that the code review occurs within the pull request itself.

While there is certainly a particular generational shift towards the use of Discord as a substitute for websites, that isn't something that tends to be shared by the wider software development community, at least those old enough to have been doing professional software development for the past couple of decades.

In my commit message, I state to report "defects" in Discord. I did not suggest to perform the PR work there.
About generational comment: I think this is not warranted in a PR. And, I'm probably as old as you are if not older.

Retested with both "-validate" flag and with actual applications.
SID is still noisy.
@angelosa
Copy link
Member

angelosa commented Aug 18, 2025

Out of sheer curiosity: how this driver behaves when testing?
You are claiming that the driver is working, and by cursory glance I bet it really isn't.

@@ -84,14 +89,21 @@ class bq4847_device : public device_t,
int m_rst_state;
int m_wdi_state;
bool m_writing;
bool has_century = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use m_ prefix on class variables to match existing style. Also initialize this variable in the constructor not the declaration (see e.g., m_writing).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

class bq4802_device : public bq4847_device
{
public:
bq4802_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before, please use right justification for references and pointers to match existing style.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the code in this class is consistent. I could modify the rest of the class to adhere to this request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not consistent with respect to the spacing around * and & tokens.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

//memcpy(m_iopage[1], m_font, 0x800);
for (int i=0;i<0x800;i++)
{
m_iopage[1]->write(i, m_font->as_u8(i));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really what happens, or should the font ROM be decoded where m_iopage[1] is currently being decoded?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The font is loaded at boot time. Users can modify the font at run time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This answer doesn't address the intent of the question. It's very unlikely that hardware performs copy of this data into RAM. What does the hardware do, if anything? What does "loaded at boot time" mean?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implement with closed-source FPGA logic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the loop and replaced with memcpy, using m_font->base() method.

0xf6, 0xf7, 0xf7, 0xf8, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xff
};

memcpy(m_iopage[0]->pointer(), gamma_1_8, 256);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this gamma table in hardware?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gamma table is used to correct the display colors. When gamma is enabled in the display register, all the colors displayed are adjusted according to this indexed table.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand what a gamma table is, I'm asking what hardware is involved in implementing it? Again, it's very unlikely that hardware is doing an arbitrary memcpy() from somewhere into RAM. Is it a RAMDAC or some other device with a fixed or programmable table that should be emulated?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implemented with closed-source FPGA logic.


rgb_t tiny_vicky_video_device::get_text_lut(uint8_t color_index, bool fg, bool gamma)
{
uint8_t red = iopage0_ptr[(fg ? 0x1800 : 0x1840) + color_index * 4 + 2];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is iopage0_ptr really pointing to a palette or RAMDAC device here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a color Look Up Table (LUT), indeed like a palette. But only 16 colors for foreground and 16 colors for background. Each color is represented by 4 bytes: blue, green, red, and alpha (alpha is ignore by the machine so far).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a color Look Up Table (LUT), indeed like a palette. But only 16 colors for foreground and 16 colors for background. Each color is represented by 4 bytes: blue, green, red, and alpha (alpha is ignore by the machine so far).

Perfect use case for a palette_device. The final bitmap should be 32bpp, so you're solid in that regard, but iit's preferable to use a palette_device for even fairly baisc LUT remapping.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intent of the question was to prompt you to explain what the underlying hardware is, such that it could be emulated in a more realistic/accurate fashion. Functionally it's a LUT; what hardware is used to implement it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's implemented via closed-source FPGA logic.

@dtremblay
Copy link
Author

dtremblay commented Aug 19, 2025

Out of sheer curiosity: how this driver behaves when testing? You are claiming that the driver is working, and by cursory glance I bet it really isn't.

I'm not sure what you are basing your conclusion on. I wouldn't submit the PR if the system was not working. Maybe I misunderstand what you imply by "driver". I can give you a demo, if you like, via MS Teams or I could upload a video to YouTube. It works quite well on Windows, Linux and Mac - users in the community have tested this, not I.

You do need to have the ROMs of course (provided: here ). The ROMs include a disk operating system and SuperBASIC and other useful utilities. If a hard disk image is provided, applications can be loaded. The F256K machines have now been around for about two years and there are now new variants being manufactured now, for example with 65816 and 6809 processors (instead of 6502) and other sound chips.

@angelosa
Copy link
Member

I'm not sure what you are basing your conclusion on.

From your tendency of dismissing comments without actually doing anything. #14029 (comment)
The driver is clearly not doing a logical to physical translation, and I can't see how a system that expects 512 KiB can work with a single page of 8 KiB, mapped on the same place on top.

Comment on lines +66 to +67
// TODO: generate start of frame (SOF) interrupt
m_sof_irq_handler(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No logic should be present in screen_update, that will break if user frameskips.

if ((sol_reg & 1) != 0 && y == sol_line)
{
// raise an interrupt
m_sol_irq_handler(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, this needs to be moved in an emu_timer, latching with screen positions.

Comment on lines 58 to 62
cursor_counter++;
if (cursor_counter > cursor_flash_rate *2)
{
cursor_counter = 0;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use frame_number() instead of manually keeping track of the count. This will again break with frameskipping.

Comment on lines 115 to 122
m_register[reg_year] = convert_to_bcd(year);
m_register[reg_year] = convert_to_bcd(year%100);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use spaces around binary operators, like year % 100 (but not unary operators like ++x).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment on lines 34 to 37
void set_century(bool value)
{
m_century = value;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is an intrinsic characteristic of the device as opposed to an input, it shouldn’t be part of the public interface.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to protected block.

Comment on lines 399 to 402
return (regnum == reg_seconds || regnum == reg_minutes || regnum == reg_hours ||
regnum == reg_date || regnum == reg_days || regnum == reg_month
|| regnum == reg_year);
|| regnum == reg_year || regnum == reg_century);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, combined with the change to write, will change the behaviour of all devices in this file to copy the contents of what’s the century register on some devices only on an update transfer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, adding device type flags that need to be checked all over the place is an ugly way of doing things. Can you think of a way of doing this without needing intrusive checks inserted throughout the code?

Comment on lines 148 to 150
uint8_t LayerMgr0 = m_iopage0_ptr[0xD002 - 0xC000] & 0x7;
uint8_t LayerMgr1 = m_iopage0_ptr[0xD002 - 0xC000] >> 4;
uint8_t LayerMgr2 = m_iopage0_ptr[0xD003 - 0xC000] & 0x7;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use snake_case for local variables. We tend to reserve LlamaCase for template parameters.

Also, please consistently use lowercase hex digits.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.
Fixed all 0x values to lowercase.

Comment on lines +52 to +55
uint32_t tiny_vicky_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
if (m_running && m_iopage0_ptr)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this function, you really should be making an effort to at least restrict the drawing to the clipping rectangle vertically so that raster effects have a chance of working.


void tiny_vicky_video_device::draw_mouse(uint32_t *row, bool enable_gamma, uint16_t line, uint16_t width, uint16_t height)
{
uint8_t mouse_reg = m_iopage0_ptr[0xD6E0 - 0xC000];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this “I/O page” actually shared RAM, or is it a bunch of memory-mapped registers? If it’s memory-mapped registers, you should put proper read/write handlers in the address map rather than pretending it’s memory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don’t do this. MAME has documentation, you don’t need a “how to use MAME” tutorial here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn’t have a separate header for this if you aren’t realistically going to need derived classes in different translation units. Just put it all in one file in an anonymous namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants